X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fmathed%2Fmath_parser.C;h=d0d480743b0befe95c551f9f6f58b6fbf92b3650;hb=74124b4bf85af8e902b2ed844ab8b6349073e814;hp=bed701268ebbde865a98ac9219303408665d7134;hpb=132fe5e1322fbc86a32692df51eba78d6b4e479c;p=lyx.git diff --git a/src/mathed/math_parser.C b/src/mathed/math_parser.C index bed701268e..d0d480743b 100644 --- a/src/mathed/math_parser.C +++ b/src/mathed/math_parser.C @@ -16,844 +16,933 @@ */ #include -#include + #include #ifdef __GNUG__ -#pragma implementation "math_parser.h" +#pragma implementation #endif #include "math_parser.h" -#include "math_iter.h" +#include "array.h" #include "math_inset.h" +#include "math_arrayinset.h" +#include "math_bigopinset.h" +#include "math_charinset.h" +#include "math_dotsinset.h" +#include "math_decorationinset.h" +#include "math_deliminset.h" +#include "math_fracinset.h" +#include "math_funcinset.h" +#include "math_funcliminset.h" #include "math_macro.h" -#include "math_root.h" +#include "math_macrotable.h" +#include "math_macrotemplate.h" +#include "math_matrixinset.h" +#include "math_noglyphinset.h" +#include "math_rootinset.h" +#include "math_scopeinset.h" +#include "math_sqrtinset.h" +#include "math_scriptinset.h" +#include "math_sizeinset.h" +#include "math_spaceinset.h" +#include "math_sqrtinset.h" +#include "math_stackrelinset.h" +#include "math_symbolinset.h" #include "debug.h" +#include "mathed/support.h" +#include "lyxlex.h" +#include "support/lstrings.h" -enum { - FLAG_BRACE = 1, // A { needed - FLAG_BRACE_ARG = 2, // Next { is argument - FLAG_BRACE_OPT = 4, // Optional { - FLAG_BRACE_LAST = 8, // Last } ends the parsing process - FLAG_BRACK_ARG = 16, // Optional [ - FLAG_RIGHT = 32, // Next right ends the parsing process - FLAG_END = 64, // Next end ends the parsing process - FLAG_BRACE_FONT = 128, // Next } closes a font - FLAG_BRACK_END = 256 // Next ] ends the parsing process -}; +using std::istream; +using std::endl; -YYSTYPE yylval; +namespace { -static short mathed_env = LM_EN_INTEXT; +MathScriptInset * prevScriptInset(MathArray const & array) +{ + MathInset * p = array.back(); + return (p && p->isScriptInset()) ? static_cast(p) : 0; +} -char * mathed_label = 0; -char const * latex_mathenv[] = { - "math", - "displaymath", - "equation", - "eqnarray*", - "eqnarray", - "array" -}; +MathInset * lastScriptInset(MathArray & array, bool up, bool down, int limits) +{ + MathScriptInset * p = prevScriptInset(array); + if (!p) { + MathInset * b = array.back(); + if (b && b->isScriptable()) { + p = new MathScriptInset(up, down, b->clone()); + array.pop_back(); + } else { + p = new MathScriptInset(up, down); + } + array.push_back(p); + } + if (up) + p->up(true); + if (down) + p->down(down); + if (limits) + p->limits(limits); + return p; +} -char const * latex_mathspace[] = { - "!", ",", ":", ";", "quad", "qquad" -}; - -char const * latex_special_chars = "#$%&_{}"; - // These are lexical codes, not semantic enum lexcode_enum { - LexNone, - LexESC, - LexAlpha, - LexDigit, - LexBOP, // Binary operators or relations - LexMathSpace, - LexOpen, - LexClose, - LexComment, - LexArgument, - LexSpace, - LexNewLine, - LexOther, - LexSelf + LexNone, + LexESC, + LexAlpha, + LexBOP, // Binary operators or relations + LexOpen, + LexClose, + LexComment, + LexArgument, + LexSpace, + LexNewLine, + LexOther, + LexMath, + LexSelf +}; + +lexcode_enum lexcode[256]; + + +const unsigned char LM_TK_OPEN = '{'; +const unsigned char LM_TK_CLOSE = '}'; + +enum { + FLAG_BRACE = 1 << 0, // A { needed //} + FLAG_BRACE_LAST = 1 << 1, // // { Last } ends the parsing process + FLAG_RIGHT = 1 << 2, // Next right ends the parsing process + FLAG_END = 1 << 3, // Next end ends the parsing process + FLAG_BRACK_END = 1 << 5, // // [ Next ] ends the parsing process + FLAG_AMPERSAND = 1 << 6, // Next & ends the parsing process + FLAG_NEWLINE = 1 << 7, // Next \\ ends the parsing process + FLAG_ITEM = 1 << 8, // read a (possibly braced token) + FLAG_LEAVE = 1 << 9, // marker for leaving the + FLAG_OPTARG = 1 << 10 // reads an argument in [] +}; + + +struct latex_mathenv_type { + char const * name; + char const * basename; + MathInsetTypes typ; + bool numbered; + bool ams; +}; + +latex_mathenv_type latex_mathenv[] = { + {"math", "math", LM_OT_SIMPLE, 0, 0}, + {"equation*", "equation", LM_OT_EQUATION, 0, 0}, + {"equation", "equation", LM_OT_EQUATION, 1, 0}, + {"eqnarray*", "eqnarray", LM_OT_EQNARRAY, 0, 0}, + {"eqnarray", "eqnarray", LM_OT_EQNARRAY, 1, 0}, + {"align*", "align", LM_OT_ALIGN, 0, 1}, + {"align", "align", LM_OT_ALIGN, 1, 1}, + {"alignat*", "alignat", LM_OT_ALIGNAT, 0, 1}, + {"alignat", "alignat", LM_OT_ALIGNAT, 1, 1}, + {"multline*", "multline", LM_OT_MULTLINE, 0, 1}, + {"multline", "multline", LM_OT_MULTLINE, 1, 1}, + {"array", "array", LM_OT_MATRIX, 0, 1} }; -static lexcode_enum lexcode[256]; -static char yytext[256]; -static int yylineno; -static istream * yyis; -static bool yy_mtextmode= false; - -inline -char * strnew(char const * s) +int const latex_mathenv_num = sizeof(latex_mathenv)/sizeof(latex_mathenv[0]); + + + +void lexInit() { - char * s1 = new char[strlen(s) + 1]; // this leaks when not delete[]'ed - strcpy(s1, s); - return s1; + for (int i = 0; i <= 255; ++i) { + if (isdigit(i)) + lexcode[i] = LexOther; + else if (isspace(i)) + lexcode[i] = LexSpace; + else + lexcode[i] = LexAlpha; + } + + lexcode['\t'] = lexcode['\f'] = lexcode[' '] = LexSpace; + lexcode['\n'] = LexNewLine; + lexcode['%'] = LexComment; + lexcode['#'] = LexArgument; + lexcode['$'] = LexMath; + lexcode['+'] = lexcode['-'] = lexcode['*'] = lexcode['/'] + = lexcode['<'] = lexcode['>'] = lexcode['='] = LexBOP; + + lexcode['('] = lexcode[')'] = lexcode['|'] = lexcode['.'] = + lexcode['?'] = LexOther; + + lexcode['\''] = lexcode['@'] = LexAlpha; + + lexcode['['] = lexcode[']'] = lexcode['^'] = lexcode['_'] = + lexcode['&'] = LexSelf; + + lexcode['\\'] = LexESC; + lexcode['{'] = LexOpen; + lexcode['}'] = LexClose; } -static -void mathPrintError(char const * msg) + +// +// Helper class for parsing +// + + +class Parser { +public: + /// + Parser(LyXLex & lex) : is_(lex.getStream()), lineno_(lex.getLineNo()) {} + /// + Parser(istream & is) : is_(is), lineno_(0) {} + + /// + MathMacroTemplate * parse_macro(); + /// + MathMatrixInset * parse_normal(); + /// + void parse_into(MathArray & array, unsigned flags); + /// + int lineno() const { return lineno_; } + +private: + /// + int yylex(); + /// + string lexArg(unsigned char lf, bool accept_spaces = false); + /// + unsigned char getuchar(); + /// + void error(string const & msg); + /// + void parse_lines(MathGridInset * p, int col, bool numbered, bool outmost); + /// + latexkeys const * read_delim(); + +private: + /// + istream & is_; + /// + int lineno_; + + /// + int ival_; + /// + latexkeys const * lval_; + /// + string sval_; + + /// + bool curr_num_; + /// + string curr_label_; + /// + string curr_skip_; +}; + + +unsigned char Parser::getuchar() { - lyxerr << "Line ~" << yylineno << ": Math parse error: " - << msg << endl; + char c = 0; + if (!is_.good()) + lyxerr << "The input stream is not well..." << endl; + is_.get(c); + return static_cast(c); } -static -void LexInitCodes() +string Parser::lexArg(unsigned char lf, bool accept_spaces = false) { - for (int i = 0; i <= 255; ++i) { - if (isalpha(i)) lexcode[i] = LexAlpha; - else if (isdigit(i)) lexcode[i] = LexDigit; - else if (isspace(i)) lexcode[i] = LexSpace; - else lexcode[i] = LexNone; - } - - lexcode['\t'] = lexcode['\f'] = lexcode[' '] = LexSpace; - lexcode['\n'] = LexNewLine; - lexcode['%'] = LexComment; - lexcode['#'] = LexArgument; - lexcode['+'] = lexcode['-'] = lexcode['*'] = lexcode['/'] = - lexcode['<'] = lexcode['>'] = lexcode['='] = LexBOP; - - lexcode['!'] = lexcode[','] = lexcode[':'] = lexcode[';'] = LexMathSpace; - lexcode['('] = lexcode[')'] = lexcode['|'] = lexcode['.'] = lexcode['?'] = LexOther; - lexcode['\'']= LexAlpha; - - lexcode['['] = lexcode[']'] = lexcode['^'] = lexcode['_'] = - lexcode['&'] = LexSelf; - - lexcode['\\'] = LexESC; - lexcode['{'] = LexOpen; - lexcode['}'] = LexClose; + string result; + unsigned char c = 0; + while (is_.good()) { + c = getuchar(); + if (!isspace(c)) + break; + } + + if (c != lf) { + is_.putback(c); + return result; + } + + unsigned char rg = 0; + if (lf == '{') rg = '}'; + if (lf == '[') rg = ']'; + if (lf == '(') rg = ')'; + if (!rg) { + lyxerr[Debug::MATHED] << "Math parse error: unknown bracket '" + << lf << "'" << endl; + return result; + } + + int depth = 1; + do { + unsigned char c = getuchar(); + if (c == lf) + ++depth; + if (c == rg) + --depth; + if ((!isspace(c) || (c == ' ' && accept_spaces)) && depth > 0) + result += c; + } while (depth > 0 && is_.good()); + + return result; } -static -char LexGetArg(char lf, bool accept_spaces= false) +int Parser::yylex() { - char rg; - char * p = &yytext[0]; - int bcnt = 1; - unsigned char c; - char cc; - while (yyis->good()) { - yyis->get(cc); - c = cc; - if (c > ' ') { - if (!lf) lf = c; else - if (c != lf) - lyxerr << "Math parse error: unexpected '" - << c << "'" << endl; - break; - } - } - rg = (lf == '{') ? '}': ((lf == '[') ? ']': ((lf == '(') ? ')': 0)); - if (!rg) { - lyxerr << "Math parse error: unknown bracket '" - << lf << "'" << endl; - return '\0'; - } - do { - yyis->get(cc); - c = cc; - if (c == lf) ++bcnt; - if (c == rg) --bcnt; - if ((c > ' ' || (c == ' ' && accept_spaces)) && bcnt>0) *(p++) = c; - } while (bcnt > 0 && yyis->good()); - *p = '\0'; - return rg; + static bool init_done = false; + + if (!init_done) { + lexInit(); + init_done = true; + } + + while (is_.good()) { + unsigned char c = getuchar(); + //lyxerr << "reading byte: '" << c << "' code: " << lexcode[c] << endl; + + if (lexcode[c] == LexNewLine) { + ++lineno_; + continue; + } else if (lexcode[c] == LexComment) { + do { + c = getuchar(); + } while (c != '\n' && is_.good()); // eat comments + } else if (lexcode[c] == LexOther) { + ival_ = c; + return LM_TK_STR; + } else if (lexcode[c] == LexAlpha || lexcode[c] == LexSpace) { + ival_ = c; + return LM_TK_ALPHA; + } else if (lexcode[c] == LexBOP) { + ival_ = c; + return LM_TK_BOP; + } else if (lexcode[c] == LexMath) { + ival_ = 0; + return LM_TK_MATH; + } else if (lexcode[c] == LexSelf) { + return c; + } else if (lexcode[c] == LexArgument) { + c = getuchar(); + ival_ = c - '0'; + return LM_TK_ARGUMENT; + } else if (lexcode[c] == LexOpen) { + return LM_TK_OPEN; + } else if (lexcode[c] == LexClose) { + return LM_TK_CLOSE; + } else if (lexcode[c] == LexESC) { + c = getuchar(); + //lyxerr << "reading second byte: '" << c << "' code: " << lexcode[c] << endl; + string s; + s += c; + latexkeys const * l = in_word_set(s); + if (l) { + //lyxerr << "found key: " << l << endl; + //lyxerr << "found key name: " << l->name << endl; + //lyxerr << "found key token: " << l->token << endl; + lval_ = l; + ival_ = l->id; + return l->token; + } + if (lexcode[c] == LexAlpha) { + sval_.erase(); + while (lexcode[c] == LexAlpha && is_.good()) { + sval_ += c; + c = getuchar(); + } + while (lexcode[c] == LexSpace && is_.good()) + c = getuchar(); + if (lexcode[c] != LexSpace) + is_.putback(c); + + //lyxerr[Debug::MATHED] << "reading: text '" << sval_ << "'\n"; + //lyxerr << "reading: text '" << sval_ << "'\n"; + latexkeys const * l = in_word_set(sval_); + if (!l) + return LM_TK_UNDEF; + + if (l->token == LM_TK_BEGIN || l->token == LM_TK_END) { + string name = lexArg('{'); + int i = 0; + while (i < latex_mathenv_num && name != latex_mathenv[i].name) + ++i; + ival_ = i; + } else if (l->token == LM_TK_SPACE) + ival_ = l->id; + else + lval_ = l; + return l->token; + } + } + } + return 0; } -static -int yylex(void) +void Parser::error(string const & msg) { - static int init_done = 0; - unsigned char c; - char cc; - - if (!init_done) LexInitCodes(); - - while (yyis->good()) { - yyis->get(cc); - c = cc; - - if (yy_mtextmode && c == ' ') { - yylval.i= ' '; - return LM_TK_ALPHA; - } - - if (lexcode[c] == LexNewLine) { - ++yylineno; - continue; - } - - if (lexcode[c] == LexComment) - do { yyis->get(cc); c = cc; } while (c != '\n' % yyis->good()); // eat comments - - if (lexcode[c] == LexDigit || lexcode[c] == LexOther || lexcode[c] == LexMathSpace) { yylval.i = c; return LM_TK_STR; } - if (lexcode[c] == LexAlpha) { yylval.i= c; return LM_TK_ALPHA; } - if (lexcode[c] == LexBOP) { yylval.i= c; return LM_TK_BOP; } - if (lexcode[c] == LexSelf) { return c; } - if (lexcode[c] == LexArgument) { - yyis->get(cc); - c = cc; - yylval.i = c - '0'; - return LM_TK_ARGUMENT; - } - if (lexcode[c] == LexOpen) { return LM_TK_OPEN; } - if (lexcode[c] == LexClose) { return LM_TK_CLOSE; } - - if (lexcode[c] == LexESC) { - yyis->get(cc); - c = cc; - if (c == '\\') { return LM_TK_NEWLINE; } - if (c == '(') { yylval.i = LM_EN_INTEXT; return LM_TK_BEGIN; } - if (c == ')') { yylval.i = LM_EN_INTEXT; return LM_TK_END; } - if (c == '[') { yylval.i = LM_EN_DISPLAY; return LM_TK_BEGIN; } - if (c == ']') { yylval.i = LM_EN_DISPLAY; return LM_TK_END; } - if (strchr(latex_special_chars, c)) { - yylval.i = c; - return LM_TK_SPECIAL; - } - if (lexcode[c] == LexMathSpace) { - int i; - for (i = 0; i < 4 && static_cast(c) != latex_mathspace[i][0]; ++i); - yylval.i = (i < 4) ? i: 0; - return LM_TK_SPACE; - } - if (lexcode[c] == LexAlpha || lexcode[c] == LexDigit) { - char * p = &yytext[0]; - while (lexcode[c] == LexAlpha || lexcode[c] == LexDigit) { - *p = c; - yyis->get(cc); - c = cc; - ++p; - } - *p = '\0'; - if (yyis->good()) yyis->putback(c); - latexkeys * l = in_word_set (yytext, strlen(yytext)); - if (l) { - if (l->token == LM_TK_BEGIN || l->token == LM_TK_END) { - int i; - LexGetArg('{'); -// for (i = 0; i < 5 && strncmp(yytext, latex_mathenv[i], -// strlen(latex_mathenv[i])); ++i); - - for (i = 0; i < 6 && strcmp(yytext, latex_mathenv[i]); ++i); - yylval.i = i; - } else - if (l->token == LM_TK_SPACE) - yylval.i = l->id; - else - yylval.l = l; - return l->token; - } else { - yylval.s = yytext; - return LM_TK_UNDEF; - } - } - } - } - return 0; + lyxerr << "Line ~" << lineno_ << ": Math parse error: " << msg << endl; } -int parse_align(char * hor, char *) +void Parser::parse_lines(MathGridInset * p, int col, bool numbered, bool outmost) { - int nc = 0; - for (char * c = hor; c && *c > ' '; ++c) ++nc; - return nc; + // save global variables + bool const saved_num = curr_num_; + string const saved_label = curr_label_; + + for (int row = 0; true; ++row) { + // reset global variables + curr_num_ = numbered; + curr_label_.erase(); + + // reading a row + int idx = p->nargs() - p->ncols(); + for (int i = 0; i < col - 1; ++i, ++idx) + parse_into(p->cell(idx), FLAG_AMPERSAND); + parse_into(p->cell(idx), FLAG_NEWLINE | FLAG_END); + + if (outmost) { + MathMatrixInset * m = static_cast(p); + m->numbered(row, curr_num_); + m->label(row, curr_label_); + if (curr_skip_.size()) { + m->vskip(LyXLength(curr_skip_), row); + curr_skip_.erase(); + } + } + +#ifdef WITH_WARNINGS +#warning Hack! +#endif + // no newline + if (ival_ != -1) + break; + + p->appendRow(); + } + + // restore "global" variables + curr_num_ = saved_num; + curr_label_ = saved_label; } -// Accent hacks only for 0.12. Stolen from Cursor. -int accent = 0; -int nestaccent[8]; +MathMacroTemplate * Parser::parse_macro() +{ + if (yylex() != LM_TK_NEWCOMMAND) { + lyxerr << "\\newcommand expected\n"; + return 0; + } + + string name = lexArg('{').substr(1); + string arg = lexArg('['); + int narg = arg.empty() ? 0 : atoi(arg.c_str()); + MathMacroTemplate * p = new MathMacroTemplate(name, narg); + parse_into(p->cell(0), FLAG_BRACE | FLAG_BRACE_LAST); + return p; +} + -void setAccent(int ac) +MathMatrixInset * Parser::parse_normal() { - if (ac > 0 && accent < 8) { - nestaccent[accent++] = ac; - } else - accent = 0; // consumed! + MathMatrixInset * p = 0; + int t = yylex(); + + switch (t) { + case LM_TK_MATH: + case LM_TK_BEGIN: { + int i = ival_; + lyxerr[Debug::MATHED] + << "reading math environment " << i << " " + << latex_mathenv[i].name << "\n"; + + MathInsetTypes typ = latex_mathenv[i].typ; + p = new MathMatrixInset(typ); + + switch (typ) { + + case LM_OT_SIMPLE: { + curr_num_ = latex_mathenv[i].numbered; + curr_label_.erase(); + parse_into(p->cell(0), 0); + p->numbered(0, curr_num_); + p->label(0, curr_label_); + break; + } + + case LM_OT_EQUATION: { + curr_num_ = latex_mathenv[i].numbered; + curr_label_.erase(); + parse_into(p->cell(0), FLAG_END); + p->numbered(0, curr_num_); + p->label(0, curr_label_); + break; + } + + case LM_OT_EQNARRAY: { + parse_lines(p, 3, latex_mathenv[i].numbered, true); + break; + } + + case LM_OT_ALIGN: { + p->halign(lexArg('{')); + parse_lines(p, 2, latex_mathenv[i].numbered, true); + break; + } + + case LM_OT_ALIGNAT: { + p->halign(lexArg('{')); + parse_lines(p, 2, latex_mathenv[i].numbered, true); + break; + } + + default: + lyxerr[Debug::MATHED] + << "1: unknown math environment: " << typ << "\n"; + } + + break; + } + + default: + lyxerr[Debug::MATHED] + << "2 unknown math environment: " << t << "\n"; + } + + return p; } -MathedInset * doAccent(byte c, MathedTextCodes t) +latexkeys const * Parser::read_delim() { - MathedInset * ac = 0; - - for (int i = accent - 1; i >= 0; --i) { - if (i == accent - 1) - ac = new MathAccentInset(c, t, nestaccent[i]); - else - ac = new MathAccentInset(ac, nestaccent[i]); + int ld = yylex(); + //lyxerr << "found symbol: " << ld << "\n"; + latexkeys const * l = in_word_set("."); + switch (ld) { + case LM_TK_SYM: + case LM_TK_NOGLYPH: + case LM_TK_SPECIAL: + case LM_TK_BEGIN: { + l = lval_; + //lyxerr << "found key 1: '" << l << "'\n"; + //lyxerr << "found key 1: '" << l->name << "'\n"; + break; + } + case ']': + case '[': { + string s; + s += ld; + l = in_word_set(s); + //lyxerr << "found key 2: '" << l->name << "'\n"; + break; + } + case LM_TK_STR: { + string s; + s += ival_; + l = in_word_set(s); + //lyxerr << "found key 2: '" << l->name << "'\n"; + } } - accent = 0; // consumed! - - return ac; + return l; } -MathedInset * doAccent(MathedInset * p) +void Parser::parse_into(MathArray & array, unsigned flags) { - MathedInset * ac = 0; + MathTextCodes yyvarcode = LM_TC_VAR; + + int t = yylex(); + bool panic = false; + int brace = 0; + int limits = 0; + + while (t) { + //lyxerr << "t: " << t << " flags: " << flags << " i: " << ival_ + // << " '" << sval_ << "'\n"; + //array.dump(lyxerr); + //lyxerr << "\n"; + + if (flags & FLAG_ITEM) { + flags &= ~FLAG_ITEM; + if (t == LM_TK_OPEN) { + // skip the brace and regard everything to the next matching + // closing brace + t = yylex(); + ++brace; + flags |= FLAG_BRACE_LAST; + } else { + // regard only this single token + flags |= FLAG_LEAVE; + } + } + + if ((flags & FLAG_BRACE) && t != LM_TK_OPEN) { + error( + "Expected {. Maybe you forgot to enclose an argument in {}"); + panic = true; + break; + } + + switch (t) { + + case LM_TK_ALPHA: + if (!isspace(ival_) || yyvarcode == LM_TC_TEXTRM) + array.push_back(new MathCharInset(ival_, yyvarcode)); + break; + + case LM_TK_ARGUMENT: { + MathMacroArgument * p = new MathMacroArgument(ival_); + //p->code(yyvarcode); + array.push_back(p); + break; + } + + case LM_TK_SPECIAL: + array.push_back(new MathCharInset(ival_, LM_TC_SPECIAL)); + break; + + case LM_TK_STR: + array.push_back(new MathCharInset(ival_, LM_TC_CONST)); + break; + + case LM_TK_OPEN: + array.push_back(new MathScopeInset); + parse_into(array.back()->cell(0), FLAG_BRACE_LAST); + break; + + case LM_TK_CLOSE: + if (flags & FLAG_BRACE_LAST) { + flags |= FLAG_LEAVE; + } + break; + + case '[': + array.push_back(new MathCharInset('[', LM_TC_CONST)); + break; + + case ']': + if (flags & FLAG_BRACK_END) + flags |= FLAG_LEAVE; + else + array.push_back(new MathCharInset(']', LM_TC_CONST)); + break; + + case '^': + parse_into( + lastScriptInset(array, true, false, limits)->cell(0), FLAG_ITEM); + break; + + case '_': + parse_into( + lastScriptInset(array, false, true, limits)->cell(1), FLAG_ITEM); + break; + + case LM_TK_LIMIT: + limits = lval_->id; + //lyxerr << "setting limit to " << limits << "\n"; + break; + + case '&': + if (flags & FLAG_AMPERSAND) { + flags &= ~FLAG_AMPERSAND; + return; + } + lyxerr[Debug::MATHED] + << "found tab unexpectedly, array: '" << array << "'\n"; + break; + + case LM_TK_NEWLINE: + { + curr_skip_ = lexArg('['); + if (flags & FLAG_NEWLINE) { + flags &= ~FLAG_NEWLINE; + return; + } + lyxerr[Debug::MATHED] + << "found newline unexpectedly, array: '" << array << "'\n"; + break; + } + + case LM_TK_PROTECT: + break; + + case LM_TK_NOGLYPH: + case LM_TK_NOGLYPHB: + limits = 0; + array.push_back(new MathNoglyphInset(lval_)); + break; + + case LM_TK_BIGSYM: + limits = 0; + array.push_back(new MathBigopInset(lval_)); + break; + + case LM_TK_FUNCLIM: + limits = 0; + array.push_back(new MathFuncLimInset(lval_)); + break; + + case LM_TK_SYM: + limits = 0; + array.push_back(new MathSymbolInset(lval_)); + break; + + case LM_TK_BOP: + array.push_back(new MathCharInset(ival_, LM_TC_BOP)); + break; + + case LM_TK_SPACE: + if (ival_ >= 0) + array.push_back(new MathSpaceInset(ival_)); + break; + + case LM_TK_DOTS: + array.push_back(new MathDotsInset(lval_)); + break; + + case LM_TK_STACK: + { + MathStackrelInset * p = new MathStackrelInset; + parse_into(p->cell(0), FLAG_ITEM); + parse_into(p->cell(1), FLAG_ITEM); + array.push_back(p); + break; + } + + case LM_TK_FRAC: + { + MathFracInset * p = new MathFracInset; + parse_into(p->cell(0), FLAG_ITEM); + parse_into(p->cell(1), FLAG_ITEM); + array.push_back(p); + break; + } + + case LM_TK_SQRT: + { + unsigned char c = getuchar(); + if (c == '[') { + array.push_back(new MathRootInset); + parse_into(array.back()->cell(0), FLAG_BRACK_END); + parse_into(array.back()->cell(1), FLAG_ITEM); + } else { + is_.putback(c); + array.push_back(new MathSqrtInset); + parse_into(array.back()->cell(0), FLAG_ITEM); + } + break; + } + + case LM_TK_LEFT: + { + latexkeys const * l = read_delim(); + MathArray ar; + parse_into(ar, FLAG_RIGHT); + latexkeys const * r = read_delim(); + MathDelimInset * dl = new MathDelimInset(l, r); + dl->cell(0) = ar; + array.push_back(dl); + break; + } + + case LM_TK_RIGHT: + if (flags & FLAG_RIGHT) + return; + error("Unmatched right delimiter"); +// panic = true; + break; + + case LM_TK_FONT: + { + MathTextCodes t = static_cast(lval_->id); + MathArray ar; + parse_into(ar, FLAG_ITEM); + for (MathArray::iterator it = ar.begin(); it != ar.end(); ++it) + (*it)->handleFont(t); + array.push_back(ar); + break; + } + + case LM_TK_OLDFONT: + yyvarcode = static_cast(lval_->id); + break; + + case LM_TK_STY: + { + lyxerr[Debug::MATHED] << "LM_TK_STY not implemented\n"; + //MathArray tmp = array; + //MathSizeInset * p = new MathSizeInset(MathStyles(lval_->id)); + //array.push_back(p); + //parse_into(p->cell(0), FLAG_BRACE_FONT); + break; + } + + case LM_TK_DECORATION: + { + MathDecorationInset * p = new MathDecorationInset(lval_); + parse_into(p->cell(0), FLAG_ITEM); + array.push_back(p); + break; + } + + case LM_TK_NONUM: + curr_num_ = false; + break; + + case LM_TK_FUNC: + array.push_back(new MathSymbolInset(lval_)); + break; + + case LM_TK_UNDEF: + if (MathMacroTable::hasTemplate(sval_)) { + MathMacro * m = MathMacroTable::cloneTemplate(sval_); + for (int i = 0; i < m->nargs(); ++i) + parse_into(m->cell(i), FLAG_ITEM); + array.push_back(m); + m->metrics(LM_ST_TEXT); + } else + array.push_back(new MathFuncInset(sval_)); + break; + + case LM_TK_MATH: + case LM_TK_END: + return; + + case LM_TK_BEGIN: + { + int i = ival_; + MathInsetTypes typ = latex_mathenv[i].typ; + + if (typ == LM_OT_MATRIX) { + string const valign = lexArg('[') + 'c'; + string const halign = lexArg('{'); + //lyxerr << "valign: '" << valign << "'\n"; + //lyxerr << "halign: '" << halign << "'\n"; + MathArrayInset * m = new MathArrayInset(halign.size(), 1); + m->valign(valign[0]); + m->halign(halign); + + parse_lines(m, halign.size(), latex_mathenv[i].numbered, false); + array.push_back(m); + //lyxerr << "read matrix " << *m << "\n"; + break; + } else + lyxerr[Debug::MATHED] << "unknow math inset " << typ << "\n"; + break; + } - for (int i = accent - 1; i >= 0; --i) { - if (i == accent - 1) - ac = new MathAccentInset(p, nestaccent[i]); - else - ac = new MathAccentInset(ac, nestaccent[i]); + case LM_TK_MACRO: + array.push_back(MathMacroTable::cloneTemplate(lval_->name)); + break; + + case LM_TK_LABEL: + curr_label_ = lexArg('{', true); + break; + + default: + error("Unrecognized token"); + lyxerr[Debug::MATHED] << "[" << t << " " << sval_ << "]" << endl; + break; + + } // end of big switch + + if (flags & FLAG_LEAVE) { + flags &= ~FLAG_LEAVE; + break; + } + + if (panic) { + lyxerr << " Math Panic, expect problems!" << endl; + // Search for the end command. + do { + t = yylex(); + } while (is_.good() && t != LM_TK_END && t); + } else { + t = yylex(); + } } - accent = 0; // consumed! - - return ac; } -LyxArrayBase * mathed_parse(unsigned flags, LyxArrayBase * array, - MathParInset ** mtx) +void parse_end(LyXLex & lex, int lineno) { - int t = yylex(), tprev = 0; - bool panic = false; - static int plevel = -1; - static int size = LM_ST_TEXT; - MathedTextCodes varcode = LM_TC_VAR; - MathedInset * binset = 0; - static MathMacroTemplate * macro= 0; - - int brace = 0; - int acc_brace = 0; - int acc_braces[8]; - MathParInset * mt = (mtx) ? *mtx : 0;//(MathParInset*)0; - MathedRowSt * crow = (mt) ? mt->getRowSt() : 0; - - ++plevel; - if (!array) array = new LyxArrayBase; - MathedIter data(array); - while (t) { - if ((flags & FLAG_BRACE) && t != LM_TK_OPEN) { - if ((flags & FLAG_BRACK_ARG) && t == '[') { - } - else { - mathPrintError("Expected {. Maybe you forgot to enclose an argument in {}"); - panic = true; - break; - } - } - MathedInsetTypes fractype = LM_OT_FRAC; - switch (t) { - case LM_TK_ALPHA: - { - if (accent) { - data.Insert(doAccent(yylval.i, varcode)); - } else - data.Insert (yylval.i, varcode); //LM_TC_VAR); - break; - } - case LM_TK_ARGUMENT: - { - if (macro) { - data.Insert(macro->getMacroPar(yylval.i-1), LM_TC_INSET); - } - break; - } - case LM_TK_NEWCOMMAND: - { - int na = 0; - - LexGetArg('{'); - // This name lives until quitting, for that reason - // I didn't care on deleting explicitly. Later I will. - char const * name = strnew(&yytext[1]); - // ugly trick to be removed soon (lyx3) - char c; yyis->get(c); - yyis->putback(c); - if (c == '[') { - LexGetArg('['); - na = atoi(yytext); - } - macro = new MathMacroTemplate(name, na); - flags = FLAG_BRACE|FLAG_BRACE_LAST; - *mtx = macro; - macro->SetData(array); - break; - } - case LM_TK_SPECIAL: - { - data.Insert (yylval.i, LM_TC_SPECIAL); - break; - } - case LM_TK_STR: - { - if (accent) { - data.Insert(doAccent(yylval.i, LM_TC_CONST)); - } else - data.Insert (yylval.i, LM_TC_CONST); - break; - } - case LM_TK_OPEN: - { - ++brace; - if (accent && tprev == LM_TK_ACCENT) { - acc_braces[acc_brace++] = brace; - break; - } - if (flags & FLAG_BRACE_OPT) { - flags &= ~FLAG_BRACE_OPT; - flags |= FLAG_BRACE; + // Update line number + lex.setLineNo(lineno); + + // reading of end_inset + while (lex.isOK()) { + lex.nextToken(); + if (lex.getString() == "\\end_inset") + break; + lyxerr[Debug::MATHED] << "InsetFormula::Read: Garbage before \\end_inset," + " or missing \\end_inset!" << endl; } - - if (flags & FLAG_BRACE) - flags &= ~FLAG_BRACE; - else { - data.Insert ('{', LM_TC_TEX); - } - break; - } - case LM_TK_CLOSE: - { - --brace; - if (brace < 0) { - mathPrintError("Unmatching braces"); - panic = true; - break; - } - if (acc_brace && brace == acc_braces[acc_brace-1]-1) { - --acc_brace; - break; - } - if (flags & FLAG_BRACE_FONT) { - varcode = LM_TC_VAR; - yy_mtextmode = false; - flags &= ~FLAG_BRACE_FONT; - break; - } - if (brace == 0 && (flags & FLAG_BRACE_LAST)) { - --plevel; - return array; - } else { - data.Insert ('}', LM_TC_TEX); - } - break; - } - - case '[': - { - if (flags & FLAG_BRACK_ARG) { - flags &= ~FLAG_BRACK_ARG; - char rg = LexGetArg('['); - if (rg!= ']') { - mathPrintError("Expected ']'"); - panic = true; - break; - } -// if (arg) strcpy(arg, yytext); - } else - data.Insert ('['); - break; - } - case ']': - { - if (flags & FLAG_BRACK_END) { - --plevel; - return array; - } else - data.Insert (']'); - break; - } - - case '^': - { - MathParInset * p = new MathParInset(size, "", LM_OT_SCRIPT); - LyxArrayBase * ar = mathed_parse(FLAG_BRACE_OPT|FLAG_BRACE_LAST, 0); - p->SetData(ar); -// lyxerr << "UP[" << p->GetStyle() << "]" << endl; - data.Insert (p, LM_TC_UP); - break; - } - case '_': - { - MathParInset * p = new MathParInset(size, "", LM_OT_SCRIPT); - LyxArrayBase * ar = mathed_parse(FLAG_BRACE_OPT|FLAG_BRACE_LAST, 0); - p->SetData(ar); - data.Insert (p, LM_TC_DOWN); - break; - } - - case LM_TK_LIMIT: - { - if (binset) { - binset->SetLimits(bool(yylval.l->id)); - binset = 0; - } - break; - } - - case '&': // Tab - { - if ((flags & FLAG_END) && mt && data.getCol()GetColumns()-1) { - data.setNumCols(mt->GetColumns()); - data.Insert('T', LM_TC_TAB); - } else - mathPrintError("Unexpected tab"); - // debug info. [made that conditional -JMarc] - if (lyxerr.debugging(Debug::MATHED)) - lyxerr << data.getCol() << " " << mt->GetColumns() << endl; - break; - } - case LM_TK_NEWLINE: - { - if (mt && (flags & FLAG_END)) { - if (mt->Permit(LMPF_ALLOW_CR)) { - if (crow) { - crow->setNext(new MathedRowSt(mt->GetColumns()+1)); // this leaks - crow = crow->getNext(); - } - data.Insert('K', LM_TC_CR); - } else - mathPrintError("Unexpected newline"); - } - break; - } - case LM_TK_BIGSYM: - { - binset = new MathBigopInset(yylval.l->name, yylval.l->id); - data.Insert(binset); - break; - } - case LM_TK_SYM: - { - if (yylval.l->id < 256) { - MathedTextCodes tc = MathIsBOPS(yylval.l->id) ? LM_TC_BOPS: LM_TC_SYMB; - if (accent) { - data.Insert(doAccent(yylval.l->id, tc)); - } else - data.Insert (yylval.l->id, tc); - } else { - MathFuncInset * bg = new MathFuncInset(yylval.l->name); - if (accent) { - data.Insert(doAccent(bg)); - } else - data.Insert(bg, true); - } - break; - } - case LM_TK_BOP: - { - if (accent) { - data.Insert(doAccent(yylval.i, LM_TC_BOP)); - } else - data.Insert (yylval.i, LM_TC_BOP); - break; - } - case LM_TK_STY: - { - if (mt) { - mt->UserSetSize(yylval.l->id); - } - break; - } - case LM_TK_SPACE: - { - if (yylval.i >= 0) { - MathSpaceInset * sp = new MathSpaceInset(yylval.i); - data.Insert(sp); - } - break; - } - case LM_TK_DOTS: - { - MathDotsInset * p = new MathDotsInset(yylval.l->name, yylval.l->id); - data.Insert(p); - break; - } - case LM_TK_STACK: - fractype = LM_OT_STACKREL; - case LM_TK_FRAC: - { - MathFracInset * fc = new MathFracInset(fractype); - LyxArrayBase * num = mathed_parse(FLAG_BRACE|FLAG_BRACE_LAST); - LyxArrayBase * den = mathed_parse(FLAG_BRACE|FLAG_BRACE_LAST); - fc->SetData(num, den); - data.Insert(fc, LM_TC_ACTIVE_INSET); - break; - } - case LM_TK_SQRT: - { - MathParInset * rt; - - char c; yyis->get(c); - - if (c == '[') { - rt = new MathRootInset(size); - rt->setArgumentIdx(0); - rt->SetData(mathed_parse(FLAG_BRACK_END, 0, &rt)); - rt->setArgumentIdx(1); - } else { - yyis->putback(c); - rt = new MathSqrtInset(size); - } - rt->SetData(mathed_parse(FLAG_BRACE|FLAG_BRACE_LAST, 0, &rt)); - data.Insert(rt, LM_TC_ACTIVE_INSET); - break; - } - - case LM_TK_LEFT: - { - int lfd, rgd; - lfd = yylex(); - if (lfd == LM_TK_SYM || lfd == LM_TK_STR || lfd == LM_TK_BOP|| lfd == LM_TK_SPECIAL) - lfd = (lfd == LM_TK_SYM) ? yylval.l->id: yylval.i; -// lyxerr << "L[" << lfd << " " << lfd << "]"; - LyxArrayBase * a = mathed_parse(FLAG_RIGHT); - rgd = yylex(); -// lyxerr << "R[" << rgd << "]"; - if (rgd == LM_TK_SYM || rgd == LM_TK_STR || rgd == LM_TK_BOP || rgd == LM_TK_SPECIAL) - rgd = (rgd == LM_TK_SYM) ? yylval.l->id: yylval.i; - MathDelimInset * dl = new MathDelimInset(lfd, rgd); - dl->SetData(a); - data.Insert(dl, LM_TC_ACTIVE_INSET); -// lyxerr << "RL[" << lfd << " " << rgd << "]"; - break; - } - case LM_TK_RIGHT: - { - if (flags & FLAG_RIGHT) { - --plevel; - return array; - } else { - mathPrintError("Unmatched right delimiter"); -// panic = true; - } - break; - } - - case LM_TK_FONT: - { - varcode = static_cast(yylval.l->id); - yy_mtextmode = bool(varcode == LM_TC_TEXTRM); - flags |= (FLAG_BRACE|FLAG_BRACE_FONT); - break; - } - case LM_TK_WIDE: - { - MathDecorationInset * sq = new MathDecorationInset(yylval.l->id, - size); - sq->SetData(mathed_parse(FLAG_BRACE|FLAG_BRACE_LAST)); - data.Insert(sq, LM_TC_ACTIVE_INSET); - break; - } - - case LM_TK_ACCENT: setAccent(yylval.l->id); break; - - case LM_TK_NONUM: - { - if (crow) - crow->setNumbered(false); - break; - } - - case LM_TK_PMOD: - case LM_TK_FUNC: - { - MathedInset * bg = new MathFuncInset(yylval.l->name); - if (accent) { - data.Insert(t); - } else - data.Insert(bg); - break; - } - case LM_TK_FUNCLIM: - { - data.Insert(new MathFuncInset(yylval.l->name, LM_OT_FUNCLIM)); - break; - } - case LM_TK_UNDEF: - { - - MathMacro * p = - MathMacroTable::mathMTable.getMacro(yylval.s); - if (p) { - if (accent) - data.Insert(doAccent(p), p->getTCode()); - else - data.Insert(p, p->getTCode()); - for (int i = 0; p->setArgumentIdx(i); ++i) - p->SetData(mathed_parse(FLAG_BRACE|FLAG_BRACE_LAST)); - } - else { - MathedInset * q = new MathFuncInset(yylval.s, LM_OT_UNDEF); - if (accent) { - data.Insert(doAccent(q)); - } else { - data.Insert(q); - } - } - break; - } - case LM_TK_END: - { - if (mathed_env != yylval.i && yylval.i!= LM_EN_ARRAY) - mathPrintError("Unmatched environment"); - // debug info [made that conditional -JMarc] - if (lyxerr.debugging(Debug::MATHED)) - lyxerr << "[" << yylval.i << "]" << endl; - --plevel; - if (mt) { // && (flags & FLAG_END)) { - mt->SetData(array); - array = 0; - } - return array; - } - case LM_TK_BEGIN: - { - if (yylval.i == LM_EN_ARRAY) { - char ar[120], ar2[8]; - ar[0] = ar2[0] = '\0'; - char rg = LexGetArg(0); - if (rg == ']') { - strcpy(ar2, yytext); - rg = LexGetArg('{'); - } - strcpy(ar, yytext); - int nc = parse_align(ar, ar2); - MathParInset * mm = new MathMatrixInset(nc, 0); - mm->SetAlign(ar2[0], ar); - data.Insert(mm, LM_TC_ACTIVE_INSET); - mathed_parse(FLAG_END, mm->GetData(), &mm); - } else - if (yylval.i >= LM_EN_INTEXT && yylval.i<= LM_EN_EQNARRAY) { - if (plevel!= 0) { - mathPrintError("Misplaced environment"); - break; - } - if (!mt) { - mathPrintError("0 paragraph."); - panic = true; - } - - mathed_env = yylval.i; - if (mathed_env>= LM_EN_DISPLAY) { - size = LM_ST_DISPLAY; - if (mathed_env>LM_EN_EQUATION) { - mt = new MathMatrixInset(3, -1); - mt->SetAlign(' ', "rcl"); - if (mtx) *mtx = mt; - flags |= FLAG_END; -// data.Insert(' ', LM_TC_TAB); -// data.Insert(' ', LM_TC_TAB); -// data.Reset(); - } - mt->SetStyle(size); - mt->SetType(mathed_env); - crow = mt->getRowSt(); - } - -#ifdef DEBUG - lyxerr << "MATH BEGIN[" << mathed_env << "]" << endl; -#endif - } else { -// lyxerr << "MATHCRO[" << yytext << "]"; - MathMacro * p = - MathMacroTable::mathMTable.getMacro(yytext); - if (p) { - data.Insert(p, p->getTCode()); - p->setArgumentIdx(0); - mathed_parse(FLAG_END, p->GetData(), reinterpret_cast(&p)); -// for (int i = 0; p->setArgumentIdx(i); ++i) -// p->SetData(mathed_parse(FLAG_BRACE|FLAG_BRACE_LAST)); - } else - mathPrintError("Unrecognized environment"); - } - break; - } - - case LM_TK_MACRO: - { - MathedInset * p = - MathMacroTable::mathMTable.getMacro(yylval.l->name); - - if (p) { - if (accent) { - data.Insert(doAccent(p)); - } else - data.Insert(p, static_cast(p)->getTCode()); - } - break; - } - - case LM_TK_LABEL: - { - char rg = LexGetArg('\0', true); - if (rg != '}') { - mathPrintError("Expected '{'"); - // debug info - lyxerr << "[" << yytext << "]" << endl; - panic = true; - break; - } - if (crow) { - // This is removed by crow's destructor. Bad design? yes, this - // will be changed after 0.12 - crow->setLabel(strnew(yytext)); - } - else { - // where is this math_label free'ed? - // Supposedly in ~formula, another bad hack, - // give me some time please. - mathed_label = strnew(yytext); - } -#ifdef DEBUG - lyxerr << "Label[" << mathed_label << "]" << endl; -#endif - break; - } - default: - mathPrintError("Unrecognized token"); - // debug info - lyxerr << "[" << t << " " << yytext << "]" << endl; - break; - } - tprev = t; - if (panic) { - lyxerr << " Math Panic, expect problems!" << endl; - // Search for the end command. - do t = yylex (); while (t != LM_TK_END && t); - } else - t = yylex (); - - if ((flags & FLAG_BRACE_OPT)/* && t!= '^' && t!= '_'*/) { - flags &= ~FLAG_BRACE_OPT; - //data.Insert (LM_TC_CLOSE); - break; - } - } - --plevel; - return array; } +} // anonymous namespace -void mathed_parser_file(istream & is, int lineno) + + +MathArray mathed_parse_cell(string const & str) +{ + istringstream is(str.c_str()); + Parser parser(is); + MathArray ar; + parser.parse_into(ar, 0); + return ar; +} + + + +MathMacroTemplate * mathed_parse_macro(string const & str) +{ + istringstream is(str.c_str()); + Parser parser(is); + return parser.parse_macro(); +} + +MathMacroTemplate * mathed_parse_macro(istream & is) { - yyis = &is; - yylineno = lineno; - if (!MathMacroTable::built) - MathMacroTable::mathMTable.builtinMacros(); + Parser parser(is); + return parser.parse_macro(); } +MathMacroTemplate * mathed_parse_macro(LyXLex & lex) +{ + Parser parser(lex); + MathMacroTemplate * p = parser.parse_macro(); + parse_end(lex, parser.lineno()); + return p; +} + + + +MathMatrixInset * mathed_parse_normal(string const & str) +{ + istringstream is(str.c_str()); + Parser parser(is); + return parser.parse_normal(); +} + +MathMatrixInset * mathed_parse_normal(istream & is) +{ + Parser parser(is); + return parser.parse_normal(); +} -int mathed_parser_lineno() +MathMatrixInset * mathed_parse_normal(LyXLex & lex) { - return yylineno; + Parser parser(lex); + MathMatrixInset * p = parser.parse_normal(); + parse_end(lex, parser.lineno()); + return p; }