]> git.lyx.org Git - lyx.git/blob - src/mathed/math_parser.C
d0d480743b0befe95c551f9f6f58b6fbf92b3650
[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_inset.h"
29 #include "math_arrayinset.h"
30 #include "math_bigopinset.h"
31 #include "math_charinset.h"
32 #include "math_dotsinset.h"
33 #include "math_decorationinset.h"
34 #include "math_deliminset.h"
35 #include "math_fracinset.h"
36 #include "math_funcinset.h"
37 #include "math_funcliminset.h"
38 #include "math_macro.h"
39 #include "math_macrotable.h"
40 #include "math_macrotemplate.h"
41 #include "math_matrixinset.h"
42 #include "math_noglyphinset.h"
43 #include "math_rootinset.h"
44 #include "math_scopeinset.h"
45 #include "math_sqrtinset.h"
46 #include "math_scriptinset.h"
47 #include "math_sizeinset.h"
48 #include "math_spaceinset.h"
49 #include "math_sqrtinset.h"
50 #include "math_stackrelinset.h"
51 #include "math_symbolinset.h"
52 #include "debug.h"
53 #include "mathed/support.h"
54 #include "lyxlex.h"
55 #include "support/lstrings.h"
56
57 using std::istream;
58 using std::endl;
59
60
61 namespace {
62
63 MathScriptInset * prevScriptInset(MathArray const & array)
64 {
65         MathInset * p = array.back();
66         return (p && p->isScriptInset()) ? static_cast<MathScriptInset *>(p) : 0;
67 }
68
69
70 MathInset * lastScriptInset(MathArray & array, bool up, bool down, int limits)
71 {
72         MathScriptInset * p = prevScriptInset(array);
73         if (!p) {
74                 MathInset * b = array.back();
75                 if (b && b->isScriptable()) {
76                         p = new MathScriptInset(up, down, b->clone());
77                         array.pop_back();       
78                 } else {
79                         p = new MathScriptInset(up, down);
80                 }
81                 array.push_back(p);
82         }
83         if (up)
84                 p->up(true);
85         if (down)
86                 p->down(down);
87         if (limits)
88                 p->limits(limits);
89         return p;
90 }
91
92
93 // These are lexical codes, not semantic
94 enum lexcode_enum {
95         LexNone,
96         LexESC,
97         LexAlpha,
98         LexBOP,         // Binary operators or relations
99         LexOpen,
100         LexClose,
101         LexComment,
102         LexArgument,
103         LexSpace,
104         LexNewLine,
105         LexOther,
106         LexMath,
107         LexSelf
108 };
109
110 lexcode_enum lexcode[256];  
111
112
113 const unsigned char LM_TK_OPEN  = '{';
114 const unsigned char LM_TK_CLOSE = '}';
115
116 enum {
117         FLAG_BRACE      = 1 << 0,  //  A { needed              //}
118         FLAG_BRACE_LAST = 1 << 1,  //  // { Last } ends the parsing process
119         FLAG_RIGHT      = 1 << 2,  //  Next right ends the parsing process
120         FLAG_END        = 1 << 3,  //  Next end ends the parsing process
121         FLAG_BRACK_END  = 1 << 5,  //  // [ Next ] ends the parsing process
122         FLAG_AMPERSAND  = 1 << 6,  //  Next & ends the parsing process
123         FLAG_NEWLINE    = 1 << 7,  //  Next \\ ends the parsing process
124         FLAG_ITEM       = 1 << 8,  //  read a (possibly braced token)
125         FLAG_LEAVE      = 1 << 9,  //  marker for leaving the 
126         FLAG_OPTARG     = 1 << 10  //  reads an argument in []
127 };
128
129
130 struct latex_mathenv_type {
131         char const *      name;
132         char const *      basename;
133         MathInsetTypes    typ;
134         bool              numbered;
135         bool              ams;
136 };
137
138 latex_mathenv_type latex_mathenv[] = { 
139         {"math",         "math",         LM_OT_SIMPLE,   0, 0},
140         {"equation*",    "equation",     LM_OT_EQUATION, 0, 0},
141         {"equation",     "equation",     LM_OT_EQUATION, 1, 0},
142         {"eqnarray*",    "eqnarray",     LM_OT_EQNARRAY, 0, 0},
143         {"eqnarray",     "eqnarray",     LM_OT_EQNARRAY, 1, 0},
144         {"align*",       "align",        LM_OT_ALIGN,    0, 1},
145         {"align",        "align",        LM_OT_ALIGN,    1, 1},
146         {"alignat*",     "alignat",      LM_OT_ALIGNAT,  0, 1},
147         {"alignat",      "alignat",      LM_OT_ALIGNAT,  1, 1},
148         {"multline*",    "multline",     LM_OT_MULTLINE, 0, 1},
149         {"multline",     "multline",     LM_OT_MULTLINE, 1, 1},
150         {"array",        "array",        LM_OT_MATRIX,   0, 1}
151 };
152
153 int const latex_mathenv_num = sizeof(latex_mathenv)/sizeof(latex_mathenv[0]);
154
155
156
157 void lexInit()
158 {
159         for (int i = 0; i <= 255; ++i) {
160                 if (isdigit(i))
161                         lexcode[i] = LexOther;
162                 else if (isspace(i))
163                         lexcode[i] = LexSpace;
164                 else
165                         lexcode[i] = LexAlpha;
166         }
167         
168         lexcode['\t'] = lexcode['\f'] = lexcode[' '] = LexSpace;
169         lexcode['\n'] = LexNewLine;
170         lexcode['%'] = LexComment;
171         lexcode['#'] = LexArgument;
172         lexcode['$'] = LexMath;
173         lexcode['+'] = lexcode['-'] = lexcode['*'] = lexcode['/']
174                 = lexcode['<'] = lexcode['>'] = lexcode['='] = LexBOP;
175         
176         lexcode['('] = lexcode[')'] = lexcode['|'] = lexcode['.'] =
177                 lexcode['?'] = LexOther; 
178         
179         lexcode['\''] = lexcode['@'] = LexAlpha;
180         
181         lexcode['['] = lexcode[']'] = lexcode['^'] = lexcode['_'] = 
182                 lexcode['&'] = LexSelf;  
183         
184         lexcode['\\'] = LexESC;
185         lexcode['{'] = LexOpen;
186         lexcode['}'] = LexClose;
187 }
188
189
190
191 //
192 // Helper class for parsing
193 //
194
195
196 class Parser {
197 public:
198         ///
199         Parser(LyXLex & lex) : is_(lex.getStream()), lineno_(lex.getLineNo()) {}
200         ///
201         Parser(istream & is) : is_(is), lineno_(0) {}
202
203         ///
204         MathMacroTemplate * parse_macro();
205         ///
206         MathMatrixInset * parse_normal();
207         ///
208         void parse_into(MathArray & array, unsigned flags);
209         ///
210         int lineno() const { return lineno_; }
211
212 private:
213         ///
214         int yylex();
215         ///
216         string lexArg(unsigned char lf, bool accept_spaces = false);
217         ///
218         unsigned char getuchar();
219         ///
220         void error(string const & msg);
221         ///
222         void parse_lines(MathGridInset * p, int col, bool numbered, bool outmost);
223         ///
224         latexkeys const * read_delim();
225
226 private:
227         ///
228         istream & is_;
229         ///
230         int lineno_;
231
232         ///
233         int ival_;
234         ///
235         latexkeys const * lval_;
236         ///
237         string sval_;
238
239         ///
240         bool   curr_num_;
241         ///
242         string curr_label_;
243         ///
244         string curr_skip_;
245 };
246
247
248 unsigned char Parser::getuchar()
249 {
250         char c = 0;
251         if (!is_.good())
252                 lyxerr << "The input stream is not well..." << endl;
253         is_.get(c);
254         return static_cast<unsigned char>(c);
255 }
256
257
258 string Parser::lexArg(unsigned char lf, bool accept_spaces = false)
259 {
260         string result;
261         unsigned char c = 0;
262         while (is_.good()) {
263                 c = getuchar();
264                 if (!isspace(c))
265                         break;
266         }
267
268         if (c != lf) {
269                 is_.putback(c);
270                 return result;
271         }
272                 
273         unsigned char rg = 0;
274         if (lf == '{') rg = '}';
275         if (lf == '[') rg = ']';
276         if (lf == '(') rg = ')';
277         if (!rg) {
278                 lyxerr[Debug::MATHED] << "Math parse error: unknown bracket '"
279                         << lf << "'" << endl;
280                 return result;
281         }
282
283         int depth = 1;
284         do {
285                 unsigned char c = getuchar();
286                 if (c == lf)
287                         ++depth;
288                 if (c == rg)
289                         --depth;
290                 if ((!isspace(c) || (c == ' ' && accept_spaces)) && depth > 0)
291                         result += c;
292         } while (depth > 0 && is_.good());
293
294         return result;
295 }
296
297
298 int Parser::yylex()
299 {
300         static bool init_done = false;
301         
302         if (!init_done) {
303                 lexInit();
304                 init_done = true;
305         }
306         
307         while (is_.good()) {
308                 unsigned char c = getuchar();
309                 //lyxerr << "reading byte: '" << c << "' code: " << lexcode[c] << endl;
310                 
311                 if (lexcode[c] == LexNewLine) {
312                         ++lineno_; 
313                         continue;
314                 } else if (lexcode[c] == LexComment) {
315                         do {
316                                 c = getuchar();
317                         } while (c != '\n' && is_.good());  // eat comments
318                 } else if (lexcode[c] == LexOther) {
319                         ival_ = c;
320                         return LM_TK_STR;
321                 } else if (lexcode[c] == LexAlpha || lexcode[c] == LexSpace) {
322                         ival_ = c;
323                         return LM_TK_ALPHA;
324                 } else if (lexcode[c] == LexBOP) {
325                         ival_ = c;
326                         return LM_TK_BOP;
327                 } else if (lexcode[c] == LexMath) {
328                         ival_ = 0;
329                         return LM_TK_MATH;
330                 } else if (lexcode[c] == LexSelf) {
331                         return c;
332                 } else if (lexcode[c] == LexArgument) {
333                         c = getuchar();
334                         ival_ = c - '0';
335                         return LM_TK_ARGUMENT; 
336                 } else if (lexcode[c] == LexOpen) {
337                         return LM_TK_OPEN;
338                 } else if (lexcode[c] == LexClose) {
339                         return LM_TK_CLOSE;
340                 } else if (lexcode[c] == LexESC)   {
341                         c = getuchar();
342                         //lyxerr << "reading second byte: '" << c << "' code: " << lexcode[c] << endl;
343                         string s;
344                         s += c;
345                         latexkeys const * l = in_word_set(s);
346                         if (l) {
347                                 //lyxerr << "found key: " << l << endl;
348                                 //lyxerr << "found key name: " << l->name << endl;
349                                 //lyxerr << "found key token: " << l->token << endl;
350                                 lval_ = l;
351                                 ival_ = l->id;
352                                 return l->token;
353                         }
354                         if (lexcode[c] == LexAlpha) {
355                                 sval_.erase();
356                                 while (lexcode[c] == LexAlpha && is_.good()) {
357                                         sval_ += c;
358                                         c = getuchar();
359                                 }
360                                 while (lexcode[c] == LexSpace && is_.good()) 
361                                         c = getuchar();
362                                 if (lexcode[c] != LexSpace)
363                                         is_.putback(c);
364                         
365                                 //lyxerr[Debug::MATHED] << "reading: text '" << sval_ << "'\n";
366                                 //lyxerr << "reading: text '" << sval_ << "'\n";
367                                 latexkeys const * l = in_word_set(sval_);
368                                 if (!l) 
369                                         return LM_TK_UNDEF;
370
371                                 if (l->token == LM_TK_BEGIN || l->token == LM_TK_END) { 
372                                         string name = lexArg('{');
373                                         int i = 0;
374                                         while (i < latex_mathenv_num && name != latex_mathenv[i].name)
375                                                  ++i;
376                                         ival_ = i;
377                                 } else if (l->token == LM_TK_SPACE) 
378                                         ival_ = l->id;
379                                 else
380                                         lval_ = l;
381                                 return l->token;
382                         }
383                 }
384         }
385         return 0;
386 }
387
388
389 void Parser::error(string const & msg) 
390 {
391         lyxerr << "Line ~" << lineno_ << ": Math parse error: " << msg << endl;
392 }
393
394
395 void Parser::parse_lines(MathGridInset * p, int col, bool numbered, bool outmost)
396 {
397         // save global variables
398         bool   const saved_num   = curr_num_;
399         string const saved_label = curr_label_;
400
401         for (int row = 0; true; ++row) {
402                 // reset global variables
403                 curr_num_   = numbered;
404                 curr_label_.erase();
405
406                 // reading a row
407                 int idx = p->nargs() - p->ncols();
408                 for (int i = 0; i < col - 1; ++i, ++idx)
409                         parse_into(p->cell(idx), FLAG_AMPERSAND);
410                 parse_into(p->cell(idx), FLAG_NEWLINE | FLAG_END);
411
412                 if (outmost) {
413                         MathMatrixInset * m = static_cast<MathMatrixInset *>(p);
414                         m->numbered(row, curr_num_);
415                         m->label(row, curr_label_);
416                         if (curr_skip_.size()) {
417                                 m->vskip(LyXLength(curr_skip_), row);
418                                 curr_skip_.erase();
419                         }
420                 }
421
422 #ifdef WITH_WARNINGS
423 #warning Hack!
424 #endif
425                 // no newline
426                 if (ival_ != -1)
427                         break;
428
429                 p->appendRow();
430         }
431
432         // restore "global" variables
433         curr_num_   = saved_num;
434         curr_label_ = saved_label;
435 }
436
437
438 MathMacroTemplate * Parser::parse_macro()
439 {
440         if (yylex() != LM_TK_NEWCOMMAND) {
441                 lyxerr << "\\newcommand expected\n";
442                 return 0;
443         }
444
445         string name = lexArg('{').substr(1);
446         string arg  = lexArg('[');
447         int    narg = arg.empty() ? 0 : atoi(arg.c_str()); 
448         MathMacroTemplate * p = new MathMacroTemplate(name, narg);
449         parse_into(p->cell(0), FLAG_BRACE | FLAG_BRACE_LAST);
450         return p;
451 }
452
453
454 MathMatrixInset * Parser::parse_normal()
455 {
456         MathMatrixInset * p = 0;
457         int t = yylex();
458
459         switch (t) {
460                 case LM_TK_MATH:
461                 case LM_TK_BEGIN: {
462                         int i = ival_;
463                         lyxerr[Debug::MATHED]
464                                 << "reading math environment " << i << " "
465                                 << latex_mathenv[i].name << "\n";
466
467                         MathInsetTypes typ = latex_mathenv[i].typ;
468                         p = new MathMatrixInset(typ);
469
470                         switch (typ) {
471
472                                 case LM_OT_SIMPLE: {
473                                         curr_num_ = latex_mathenv[i].numbered;
474                                         curr_label_.erase();
475                                         parse_into(p->cell(0), 0);
476                                         p->numbered(0, curr_num_);
477                                         p->label(0, curr_label_);
478                                         break;
479                                 }
480
481                                 case LM_OT_EQUATION: {
482                                         curr_num_ = latex_mathenv[i].numbered;
483                                         curr_label_.erase();
484                                         parse_into(p->cell(0), FLAG_END);
485                                         p->numbered(0, curr_num_);
486                                         p->label(0, curr_label_);
487                                         break;
488                                 }
489
490                                 case LM_OT_EQNARRAY: {
491                                         parse_lines(p, 3, latex_mathenv[i].numbered, true);
492                                         break;
493                                 }
494
495                                 case LM_OT_ALIGN: {
496                                         p->halign(lexArg('{'));
497                                         parse_lines(p, 2, latex_mathenv[i].numbered, true);
498                                         break;
499                                 }
500
501                                 case LM_OT_ALIGNAT: {
502                                         p->halign(lexArg('{'));
503                                         parse_lines(p, 2, latex_mathenv[i].numbered, true);
504                                         break;
505                                 }
506
507                                 default: 
508                                         lyxerr[Debug::MATHED]
509                                                 << "1: unknown math environment: " << typ << "\n";
510                         }
511
512                         break;
513                 }
514                 
515                 default:
516                         lyxerr[Debug::MATHED]
517                                 << "2 unknown math environment: " << t << "\n";
518         }
519
520         return p;
521 }
522
523
524 latexkeys const * Parser::read_delim()
525 {
526         int ld = yylex();
527         //lyxerr << "found symbol: " << ld << "\n";
528         latexkeys const * l = in_word_set(".");
529         switch (ld) {
530                 case LM_TK_SYM:
531                 case LM_TK_NOGLYPH:
532                 case LM_TK_SPECIAL:
533                 case LM_TK_BEGIN: {
534                         l = lval_;
535                         //lyxerr << "found key 1: '" << l << "'\n";
536                         //lyxerr << "found key 1: '" << l->name << "'\n";
537                         break;
538                 }
539                 case ']':
540                 case '[': {
541                         string s;
542                         s += ld;
543                         l = in_word_set(s);
544                         //lyxerr << "found key 2: '" << l->name << "'\n";
545                         break;
546                 }
547                 case LM_TK_STR: {
548                         string s;
549                         s += ival_;
550                         l = in_word_set(s);
551                         //lyxerr << "found key 2: '" << l->name << "'\n";
552                 }
553         }
554         return l;
555 }
556
557
558 void Parser::parse_into(MathArray & array, unsigned flags)
559 {
560         MathTextCodes yyvarcode   = LM_TC_VAR;
561
562         int  t      = yylex();
563         bool panic  = false;
564         int  brace  = 0;
565         int  limits = 0;
566
567         while (t) {
568                 //lyxerr << "t: " << t << " flags: " << flags << " i: " << ival_
569                 //      << " '" << sval_ << "'\n";
570                 //array.dump(lyxerr);
571                 //lyxerr << "\n";
572
573                 if (flags & FLAG_ITEM) {
574                         flags &= ~FLAG_ITEM;
575                         if (t == LM_TK_OPEN) { 
576                                 // skip the brace and regard everything to the next matching
577                                 // closing brace
578                                 t = yylex();
579                                 ++brace;
580                                 flags |= FLAG_BRACE_LAST;
581                         } else {
582                                 // regard only this single token
583                                 flags |= FLAG_LEAVE;
584                         }
585                 }
586
587                 if ((flags & FLAG_BRACE) && t != LM_TK_OPEN) {
588                         error(
589                                 "Expected {. Maybe you forgot to enclose an argument in {}");
590                         panic = true;
591                         break;
592                 }
593
594                 switch (t) {
595                         
596                 case LM_TK_ALPHA:
597                         if (!isspace(ival_) || yyvarcode == LM_TC_TEXTRM)
598                                 array.push_back(new MathCharInset(ival_, yyvarcode));
599                         break;
600
601                 case LM_TK_ARGUMENT: {
602                         MathMacroArgument * p = new MathMacroArgument(ival_);
603                         //p->code(yyvarcode);
604                         array.push_back(p);
605                         break;
606                 }
607
608                 case LM_TK_SPECIAL:
609                         array.push_back(new MathCharInset(ival_, LM_TC_SPECIAL));
610                         break;
611
612                 case LM_TK_STR:
613                         array.push_back(new MathCharInset(ival_, LM_TC_CONST));
614                         break;
615
616                 case LM_TK_OPEN:
617                         array.push_back(new MathScopeInset);
618                         parse_into(array.back()->cell(0), FLAG_BRACE_LAST);
619                         break;
620
621                 case LM_TK_CLOSE:
622                         if (flags & FLAG_BRACE_LAST) {
623                                 flags |= FLAG_LEAVE;
624                         }
625                         break;
626                 
627                 case '[':
628                         array.push_back(new MathCharInset('[', LM_TC_CONST));
629                         break;
630
631                 case ']':
632                         if (flags & FLAG_BRACK_END)
633                                 flags |= FLAG_LEAVE;
634                         else 
635                                 array.push_back(new MathCharInset(']', LM_TC_CONST));
636                         break;
637                 
638                 case '^':
639                         parse_into(
640                                 lastScriptInset(array, true, false, limits)->cell(0), FLAG_ITEM);
641                         break;
642                 
643                 case '_':
644                         parse_into(
645                                 lastScriptInset(array, false, true, limits)->cell(1), FLAG_ITEM);
646                         break;
647                 
648                 case LM_TK_LIMIT:
649                         limits = lval_->id;
650                         //lyxerr << "setting limit to " << limits << "\n";
651                         break;
652                 
653                 case '&':
654                         if (flags & FLAG_AMPERSAND) {
655                                 flags &= ~FLAG_AMPERSAND;
656                                 return;
657                         }
658                         lyxerr[Debug::MATHED]
659                                 << "found tab unexpectedly, array: '" << array << "'\n";
660                         break;
661                 
662                 case LM_TK_NEWLINE:
663                 {
664                         curr_skip_ = lexArg('[');
665                         if (flags & FLAG_NEWLINE) {
666                                 flags &= ~FLAG_NEWLINE;
667                                 return;
668                         }
669                         lyxerr[Debug::MATHED]
670                                 << "found newline unexpectedly, array: '" << array << "'\n";
671                         break;
672                 }
673                 
674                 case LM_TK_PROTECT: 
675                         break;
676
677                 case LM_TK_NOGLYPH: 
678                 case LM_TK_NOGLYPHB: 
679                         limits = 0;
680                         array.push_back(new MathNoglyphInset(lval_));
681                         break;
682
683                 case LM_TK_BIGSYM:  
684                         limits = 0;
685                         array.push_back(new MathBigopInset(lval_));
686                         break;
687
688                 case LM_TK_FUNCLIM:
689                         limits = 0;
690                         array.push_back(new MathFuncLimInset(lval_));
691                         break;
692
693                 case LM_TK_SYM:
694                         limits = 0;
695                         array.push_back(new MathSymbolInset(lval_));
696                         break;
697
698                 case LM_TK_BOP:
699                         array.push_back(new MathCharInset(ival_, LM_TC_BOP));
700                         break;
701
702                 case LM_TK_SPACE:
703                         if (ival_ >= 0) 
704                                 array.push_back(new MathSpaceInset(ival_));
705                         break;
706
707                 case LM_TK_DOTS:
708                         array.push_back(new MathDotsInset(lval_));
709                         break;
710                 
711                 case LM_TK_STACK:
712                 {
713                         MathStackrelInset * p = new MathStackrelInset;
714                         parse_into(p->cell(0), FLAG_ITEM);
715                         parse_into(p->cell(1), FLAG_ITEM);
716                         array.push_back(p);
717                         break;
718                 }
719
720                 case LM_TK_FRAC:
721                 {
722                         MathFracInset * p = new MathFracInset;
723                         parse_into(p->cell(0), FLAG_ITEM);
724                         parse_into(p->cell(1), FLAG_ITEM);
725                         array.push_back(p);
726                         break;
727                 }
728
729                 case LM_TK_SQRT:
730                 {
731                         unsigned char c = getuchar();
732                         if (c == '[') {
733                                 array.push_back(new MathRootInset);
734                                 parse_into(array.back()->cell(0), FLAG_BRACK_END);
735                                 parse_into(array.back()->cell(1), FLAG_ITEM);
736                         } else {
737                                 is_.putback(c);
738                                 array.push_back(new MathSqrtInset);
739                                 parse_into(array.back()->cell(0), FLAG_ITEM);
740                         }
741                         break;
742                 }
743                 
744                 case LM_TK_LEFT:
745                 {
746                         latexkeys const * l = read_delim();
747                         MathArray ar;
748                         parse_into(ar, FLAG_RIGHT);
749                         latexkeys const * r = read_delim();
750                         MathDelimInset * dl = new MathDelimInset(l, r);
751                         dl->cell(0) = ar;
752                         array.push_back(dl);
753                         break;
754                 }
755                 
756                 case LM_TK_RIGHT:
757                         if (flags & FLAG_RIGHT)
758                                 return;
759                         error("Unmatched right delimiter");
760 //        panic = true;
761                         break;
762                 
763                 case LM_TK_FONT:
764                 {
765                         MathTextCodes t = static_cast<MathTextCodes>(lval_->id);
766                         MathArray ar;
767                         parse_into(ar, FLAG_ITEM);
768                         for (MathArray::iterator it = ar.begin(); it != ar.end(); ++it)
769                                 (*it)->handleFont(t);
770                         array.push_back(ar);
771                         break;
772                 }
773
774                 case LM_TK_OLDFONT:
775                         yyvarcode = static_cast<MathTextCodes>(lval_->id);
776                         break;
777
778                 case LM_TK_STY:
779                 {
780                         lyxerr[Debug::MATHED] << "LM_TK_STY not implemented\n";
781                         //MathArray tmp = array;
782                         //MathSizeInset * p = new MathSizeInset(MathStyles(lval_->id));
783                         //array.push_back(p);
784                         //parse_into(p->cell(0), FLAG_BRACE_FONT);
785                         break; 
786                 }
787
788                 case LM_TK_DECORATION:
789                 {  
790                         MathDecorationInset * p = new MathDecorationInset(lval_);
791                         parse_into(p->cell(0), FLAG_ITEM);
792                         array.push_back(p);
793                         break;
794                 }
795                         
796                 case LM_TK_NONUM:
797                         curr_num_ = false;
798                         break;
799                 
800                 case LM_TK_FUNC:
801                         array.push_back(new MathSymbolInset(lval_));
802                         break;
803                 
804                 case LM_TK_UNDEF: 
805                         if (MathMacroTable::hasTemplate(sval_)) {
806                                 MathMacro * m = MathMacroTable::cloneTemplate(sval_);
807                                 for (int i = 0; i < m->nargs(); ++i) 
808                                         parse_into(m->cell(i), FLAG_ITEM);
809                                 array.push_back(m);
810                                 m->metrics(LM_ST_TEXT);
811                         } else
812                                 array.push_back(new MathFuncInset(sval_));
813                         break;
814                 
815                 case LM_TK_MATH:
816                 case LM_TK_END:
817                         return;
818
819                 case LM_TK_BEGIN:
820                 {
821                         int i = ival_;
822                         MathInsetTypes typ = latex_mathenv[i].typ;
823
824                         if (typ == LM_OT_MATRIX) {
825                                 string const valign = lexArg('[') + 'c';
826                                 string const halign = lexArg('{');
827                                 //lyxerr << "valign: '" << valign << "'\n";
828                                 //lyxerr << "halign: '" << halign << "'\n";
829                                 MathArrayInset * m = new MathArrayInset(halign.size(), 1);
830                                 m->valign(valign[0]);
831                                 m->halign(halign);
832
833                                 parse_lines(m, halign.size(), latex_mathenv[i].numbered, false);
834                                 array.push_back(m);
835                                 //lyxerr << "read matrix " << *m << "\n";       
836                                 break;
837                         } else 
838                                 lyxerr[Debug::MATHED] << "unknow math inset " << typ << "\n";   
839                         break;
840                 }
841         
842                 case LM_TK_MACRO:
843                         array.push_back(MathMacroTable::cloneTemplate(lval_->name));
844                         break;
845                 
846                 case LM_TK_LABEL:
847                         curr_label_ = lexArg('{', true);
848                         break;
849                 
850                 default:
851                         error("Unrecognized token");
852                         lyxerr[Debug::MATHED] << "[" << t << " " << sval_ << "]" << endl;
853                         break;
854
855                 } // end of big switch
856
857                 if (flags & FLAG_LEAVE) {
858                         flags &= ~FLAG_LEAVE;
859                         break;
860                 }
861
862                 if (panic) {
863                         lyxerr << " Math Panic, expect problems!" << endl;
864                         //   Search for the end command. 
865                         do {
866                                 t = yylex();
867                         } while (is_.good() && t != LM_TK_END && t);
868                 } else {
869                         t = yylex();
870                 }
871         }
872 }
873
874
875 void parse_end(LyXLex & lex, int lineno)
876 {
877         // Update line number
878         lex.setLineNo(lineno);
879
880         // reading of end_inset
881         while (lex.isOK()) {
882                 lex.nextToken();
883                 if (lex.getString() == "\\end_inset")
884                         break;
885                 lyxerr[Debug::MATHED] << "InsetFormula::Read: Garbage before \\end_inset,"
886                         " or missing \\end_inset!" << endl;
887         }
888 }
889
890 } // anonymous namespace
891
892
893
894 MathArray mathed_parse_cell(string const & str)
895 {
896         istringstream is(str.c_str());
897         Parser parser(is);
898         MathArray ar;
899         parser.parse_into(ar, 0);
900         return ar;
901 }
902
903
904
905 MathMacroTemplate * mathed_parse_macro(string const & str)
906 {
907         istringstream is(str.c_str());
908         Parser parser(is);
909         return parser.parse_macro();
910 }
911
912 MathMacroTemplate * mathed_parse_macro(istream & is)
913 {
914         Parser parser(is);
915         return parser.parse_macro();
916 }
917
918 MathMacroTemplate * mathed_parse_macro(LyXLex & lex)
919 {
920         Parser parser(lex);
921         MathMacroTemplate * p = parser.parse_macro();
922         parse_end(lex, parser.lineno());
923         return p;
924 }
925
926
927
928 MathMatrixInset * mathed_parse_normal(string const & str)
929 {
930         istringstream is(str.c_str());
931         Parser parser(is);
932         return parser.parse_normal();
933 }
934
935 MathMatrixInset * mathed_parse_normal(istream & is)
936 {
937         Parser parser(is);
938         return parser.parse_normal();
939 }
940
941 MathMatrixInset * mathed_parse_normal(LyXLex & lex)
942 {
943         Parser parser(lex);
944         MathMatrixInset * p = parser.parse_normal();
945         parse_end(lex, parser.lineno());
946         return p;
947 }
948