X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fmathed%2Fmath_extern.C;h=f595b1b1686d040165163cac6a3640b5f3fa61db;hb=254272868f1d891b9d0a778f871afb23cce84081;hp=0e0a5280124af19ad0824db6fbbf10e2c252878a;hpb=fc1b3149985a0f94cceaa502e86072c0984e362e;p=lyx.git diff --git a/src/mathed/math_extern.C b/src/mathed/math_extern.C index 0e0a528012..f595b1b168 100644 --- a/src/mathed/math_extern.C +++ b/src/mathed/math_extern.C @@ -2,28 +2,36 @@ // information" from the unstructered layout-oriented stuff in an // MathArray. -#include +#include #include "math_amsarrayinset.h" +#include "math_arrayinset.h" #include "math_charinset.h" #include "math_deliminset.h" #include "math_diffinset.h" #include "math_exfuncinset.h" #include "math_exintinset.h" -#include "math_funcinset.h" #include "math_fracinset.h" #include "math_matrixinset.h" #include "math_mathmlstream.h" +#include "math_numberinset.h" #include "math_scriptinset.h" #include "math_stringinset.h" #include "math_symbolinset.h" +#include "math_unknowninset.h" +#include "math_parser.h" #include "Lsstream.h" #include "debug.h" +#include "support/lyxlib.h" +#include "support/systemcall.h" +#include "support/filetools.h" +#include using std::ostream; using std::istringstream; using std::find_if; +using std::endl; ostream & operator<<(ostream & os, MathArray const & ar) @@ -120,18 +128,13 @@ MathScriptInset const * asScript(MathArray::const_iterator it) // returns sequence of char with same code starting at it up to end // it might be less, though... -MathArray::const_iterator charSequence(MathArray::const_iterator it, - MathArray::const_iterator end, string & s, MathTextCodes & c) -{ - MathCharInset const * p = (*it)->asCharInset(); - c = p->code(); - for (; it != end; ++it) { - p = (*it)->asCharInset(); - if (!p || p->code() != c) - break; - s += p->getChar(); - } - return it; +string charSequence + (MathArray::const_iterator it, MathArray::const_iterator end) +{ + string s; + for (; it != end && (*it)->asCharInset(); ++it) + s += (*it)->getChar(); + return s; } @@ -139,18 +142,11 @@ void extractStrings(MathArray & ar) { //lyxerr << "\nStrings from: " << ar << "\n"; for (MathArray::size_type i = 0; i < ar.size(); ++i) { - MathArray::iterator it = ar.begin() + i; - if (!(*it)->asCharInset()) + if (!ar[i]->asCharInset()) continue; - - // create proper string inset - MathStringInset * p = new MathStringInset; - MathArray::const_iterator - jt = charSequence(it, ar.end(), p->str_, p->code_); - - // clean up - (*it).reset(p); - ar.erase(i + 1, jt - ar.begin()); + string s = charSequence(ar.begin() + i, ar.end()); + ar[i].reset(new MathStringInset(s)); + ar.erase(i + 1, i + s.size()); } //lyxerr << "\nStrings to: " << ar << "\n"; } @@ -207,22 +203,16 @@ bool extractString(MathInset * p, string & str) // convert this inset somehow to a number bool extractNumber(MathArray const & ar, int & i) { - string s; - MathTextCodes c; - charSequence(ar.begin(), ar.end(), s, c); - istringstream is(s.c_str()); + istringstream is(charSequence(ar.begin(), ar.end()).c_str()); is >> i; return is; } -bool extractNumber(MathArray const & ar, double & i) +bool extractNumber(MathArray const & ar, double & d) { - string s; - MathTextCodes c; - charSequence(ar.begin(), ar.end(), s, c); - istringstream is(s.c_str()); - is >> i; + istringstream is(charSequence(ar.begin(), ar.end()).c_str()); + is >> d; return is; } @@ -341,18 +331,75 @@ void extractExps(MathArray & ar) if (!sup || sup->hasDown()) continue; - // create a proper exp-inset as replacement - MathExFuncInset * func = new MathExFuncInset("exp"); - func->cell(0) = sup->cell(1); - - // clean up - (*it).reset(func); + // create a proper exp-inset as replacement + *it = new MathExFuncInset("exp", sup->cell(1)); ar.erase(it + 1); } //lyxerr << "\nExps to: " << ar << "\n"; } +// +// extract det(...) from |matrix| +// +void extractDets(MathArray & ar) +{ + //lyxerr << "\ndet from: " << ar << "\n"; + for (MathArray::iterator it = ar.begin(); it != ar.end(); ++it) { + MathDelimInset * del = (*it)->asDelimInset(); + if (!del) + continue; + if (!del->isAbs()) + continue; + *it = new MathExFuncInset("det", del->cell(0)); + } + //lyxerr << "\ndet to: " << ar << "\n"; +} + + +// +// search numbers +// + +bool isDigitOrSimilar(char c) +{ + return ('0' <= c && c <= '9') || c == '.'; +} + + +// returns sequence of digits +string digitSequence + (MathArray::const_iterator it, MathArray::const_iterator end) +{ + string s; + for (; it != end && (*it)->asCharInset(); ++it) { + if (!isDigitOrSimilar((*it)->getChar())) + break; + s += (*it)->getChar(); + } + return s; +} + + +void extractNumbers(MathArray & ar) +{ + //lyxerr << "\nNumbers from: " << ar << "\n"; + for (MathArray::size_type i = 0; i < ar.size(); ++i) { + if (!ar[i]->asCharInset()) + continue; + if (!isDigitOrSimilar(ar[i]->asCharInset()->getChar())) + continue; + + string s = digitSequence(ar.begin() + i, ar.end()); + + ar[i].reset(new MathNumberInset(s)); + ar.erase(i + 1, i + s.size()); + } + //lyxerr << "\nNumbers to: " << ar << "\n"; +} + + + // // search deliminiters // @@ -371,9 +418,7 @@ bool testCloseParan(MathInset * p) MathInset * replaceDelims(const MathArray & ar) { - MathDelimInset * del = new MathDelimInset("(", ")"); - del->cell(0) = ar; - return del; + return new MathDelimInset("(", ")", ar); } @@ -407,9 +452,9 @@ void extractFunctions(MathArray & ar) string name; // is it a function? - if ((*it)->asFuncInset()) { + if ((*it)->asUnknownInset()) { // it certainly is if it is well known... - name = (*it)->asFuncInset()->name(); + name = (*it)->asUnknownInset()->name(); } else { // is this a user defined function? // it it probably not, if it doesn't have a name. @@ -668,7 +713,7 @@ void extractDiff(MathArray & ar) MathArray::iterator jt = it + 1; //int n = 1; MathArray & numer = f->cell(0); - if (numer.size() > 1 && numer.at(1)->asScriptInset()) { + if (numer.size() > 1 && numer[1]->asScriptInset()) { // this is something like d^n f(x) / d... or d^n / d... // FIXME //n = 1; @@ -724,9 +769,11 @@ void extractDiff(MathArray & ar) void extractStructure(MathArray & ar) { splitScripts(ar); + extractNumbers(ar); extractMatrices(ar); extractDelims(ar); extractFunctions(ar); + extractDets(ar); extractIntegrals(ar); extractSums(ar); extractDiff(ar); @@ -821,3 +868,201 @@ void mathmlize(MathArray const & dat, MathMLStream & os) os << ETag("mrow"); } } + + + + +namespace { + + string captureOutput(string const & cmd, string const & data) + { + string outfile = lyx::tempName(string(), "mathextern"); + string full = "echo '" + data + "' | (" + cmd + ") > " + outfile; + lyxerr << "calling: " << full << endl; + Systemcall dummy; + dummy.startscript(Systemcall::Wait, full); + string out = GetFileContents(outfile); + lyx::unlink(outfile); + lyxerr << "result: '" << out << "'" << endl; + return out; + } + + + MathArray pipeThroughMaple(string const & extra, MathArray const & ar) + { + string header = "readlib(latex):\n"; + + // remove the \\it for variable names + //"#`latex/csname_font` := `\\it `:" + header += + "`latex/csname_font` := ``:\n"; + + // export matrices in (...) instead of [...] + header += + "`latex/latex/matrix` := " + "subs(`[`=`(`, `]`=`)`," + "eval(`latex/latex/matrix`)):\n"; + + // replace \\cdots with proper '*' + header += + "`latex/latex/*` := " + "subs(`\\,`=`\\cdot `," + "eval(`latex/latex/*`)):\n"; + + // remove spurious \\noalign{\\medskip} in matrix output + header += + "`latex/latex/matrix`:= " + "subs(`\\\\\\\\\\\\noalign{\\\\medskip}` = `\\\\\\\\`," + "eval(`latex/latex/matrix`)):\n"; + + //"#`latex/latex/symbol` " + // " := subs((\\'_\\' = \\'`\\_`\\',eval(`latex/latex/symbol`)): "; + + string trailer = "quit;"; + ostringstream os; + MapleStream ms(os); + ms << ar; + string expr = os.str().c_str(); + lyxerr << "ar: '" << ar << "'\n"; + lyxerr << "ms: '" << os.str() << "'\n"; + + for (int i = 0; i < 100; ++i) { // at most 100 attempts + // try to fix missing '*' the hard way by using mint + // + // ... > echo "1A;" | mint -i 1 -S -s -q + // on line 1: 1A; + // ^ syntax error - + // Probably missing an operator such as * p + // + lyxerr << "checking expr: '" << expr << "'\n"; + string out = captureOutput("mint -i 1 -S -s -q -q", expr + ";"); + if (out.empty()) + break; // expression syntax is ok + istringstream is(out.c_str()); + string line; + getline(is, line); + if (line.find("on line") != 0) + break; // error message not identified + getline(is, line); + string::size_type pos = line.find('^'); + if (pos == string::npos || pos < 15) + break; // caret position not found + pos -= 15; // skip the "on line ..." part + if (expr[pos] == '*' || (pos > 0 && expr[pos - 1] == '*')) + break; // two '*' in a row are definitely bad + expr.insert(pos, "*"); + } + + string full = "latex(" + extra + '(' + expr + "));"; + string out = captureOutput("maple -q", header + full + trailer); + + // change \_ into _ + + // + MathArray res; + mathed_parse_cell(res, out); + return res; + } + + + MathArray pipeThroughOctave(string const &, MathArray const & ar) + { + ostringstream os; + OctaveStream vs(os); + vs << ar; + string expr = os.str().c_str(); + string out; + + lyxerr << "pipe: ar: '" << ar << "'\n"; + lyxerr << "pipe: expr: '" << expr << "'\n"; + + for (int i = 0; i < 100; ++i) { // at most 100 attempts + // + // try to fix missing '*' the hard way + // parse error: + // >>> ([[1 2 3 ];[2 3 1 ];[3 1 2 ]])([[1 2 3 ];[2 3 1 ];[3 1 2 ]]) + // ^ + // + lyxerr << "checking expr: '" << expr << "'\n"; + out = captureOutput("octave -q 2>&1", expr); + lyxerr << "checking out: '" << out << "'\n"; + + // leave loop if expression syntax is probably ok + if (out.find("parse error:") == string::npos) + break; + + // search line with single caret + istringstream is(out.c_str()); + string line; + while (is) { + getline(is, line); + lyxerr << "skipping line: '" << line << "'\n"; + if (line.find(">>> ") != string::npos) + break; + } + + // found line with error, next line is the one with caret + getline(is, line); + string::size_type pos = line.find('^'); + lyxerr << "caret line: '" << line << "'\n"; + lyxerr << "found caret at pos: '" << pos << "'\n"; + if (pos == string::npos || pos < 4) + break; // caret position not found + pos -= 4; // skip the ">>> " part + if (expr[pos] == '*') + break; // two '*' in a row are definitely bad + expr.insert(pos, "*"); + } + + if (out.size() < 6) + return MathArray(); + + // remove 'ans = ' + out = out.substr(6); + + // parse output as matrix or single number + MathAtom at(new MathArrayInset("array", out)); + MathArrayInset const * mat = at.nucleus()->asArrayInset(); + MathArray res; + if (mat->ncols() == 1 && mat->nrows() == 1) + res.push_back(mat->cell(0)); + else { + res.push_back(MathAtom(new MathDelimInset("(", ")"))); + res.back()->cell(0).push_back(at); + } + return res; + } + +} + + +MathArray pipeThroughExtern(string const & lang, string const & extra, + MathArray const & ar) +{ + if (lang == "octave") + return pipeThroughOctave(extra, ar); + + if (lang == "maple") + return pipeThroughMaple(extra, ar); + + // create normalized expression + ostringstream os; + NormalStream ns(os); + os << "[" << extra << ' '; + ns << ar; + os << "]"; + string data = os.str().c_str(); + + // search external script + string file = LibFileSearch("mathed", "extern_" + lang); + if (file.empty()) { + lyxerr << "converter to '" << lang << "' not found\n"; + return MathArray(); + } + + // run external sript + string out = captureOutput(file, data); + MathArray res; + mathed_parse_cell(res, out); + return res; +}