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