2003-08-19 10:04:35 +00:00
|
|
|
|
/**
|
|
|
|
|
* \file math.C
|
|
|
|
|
* This file is part of LyX, the document processor.
|
|
|
|
|
* Licence details can be found in the file COPYING.
|
|
|
|
|
*
|
|
|
|
|
* \author Andr<EFBFBD> P<EFBFBD>nitz
|
|
|
|
|
*
|
2003-08-23 00:17:00 +00:00
|
|
|
|
* Full author contact details are available in file CREDITS.
|
2003-04-17 09:47:21 +00:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// {[(
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
|
|
#include "tex2lyx.h"
|
|
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
|
|
using std::cerr;
|
|
|
|
|
using std::endl;
|
2003-09-08 00:33:41 +00:00
|
|
|
|
|
2003-04-17 09:47:21 +00:00
|
|
|
|
using std::ostream;
|
2003-06-30 11:36:08 +00:00
|
|
|
|
using std::string;
|
2003-04-17 09:47:21 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool is_math_env(string const & name)
|
|
|
|
|
{
|
|
|
|
|
static char const * known_math_envs[] = { "equation", "equation*",
|
2003-05-19 07:22:16 +00:00
|
|
|
|
"eqnarray", "eqnarray*", "align", "align*", "gather", "gather*",
|
2003-10-23 11:46:33 +00:00
|
|
|
|
"multline", "multline*", "math", "displaymath", "flalign", "flalign*",
|
|
|
|
|
// These require extra args
|
|
|
|
|
"alignat", "alignat*", "xalignat", "xalignat*", "xxalignat",
|
|
|
|
|
0};
|
2003-04-17 09:47:21 +00:00
|
|
|
|
|
|
|
|
|
for (char const ** what = known_math_envs; *what; ++what)
|
|
|
|
|
if (*what == name)
|
|
|
|
|
return true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void parse_math(Parser & p, ostream & os, unsigned flags, const mode_type mode)
|
|
|
|
|
{
|
|
|
|
|
while (p.good()) {
|
2003-04-23 15:14:43 +00:00
|
|
|
|
Token const & t = p.get_token();
|
2003-04-17 09:47:21 +00:00
|
|
|
|
|
|
|
|
|
#ifdef FILEDEBUG
|
|
|
|
|
cerr << "t: " << t << " flags: " << flags << "\n";
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (flags & FLAG_ITEM) {
|
|
|
|
|
if (t.cat() == catSpace)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
flags &= ~FLAG_ITEM;
|
|
|
|
|
if (t.cat() == catBegin) {
|
|
|
|
|
// skip the brace and collect everything to the next matching
|
|
|
|
|
// closing brace
|
|
|
|
|
flags |= FLAG_BRACE_LAST;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// handle only this single token, leave the loop if done
|
|
|
|
|
flags |= FLAG_LEAVE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// cat codes
|
|
|
|
|
//
|
|
|
|
|
if (t.cat() == catMath) {
|
|
|
|
|
if (mode == MATHTEXT_MODE) {
|
|
|
|
|
// we are inside some text mode thingy, so opening new math is allowed
|
2003-04-23 15:14:43 +00:00
|
|
|
|
Token const & n = p.get_token();
|
2003-04-17 09:47:21 +00:00
|
|
|
|
if (n.cat() == catMath) {
|
|
|
|
|
// TeX's $$...$$ syntax for displayed math
|
|
|
|
|
os << "\\[";
|
|
|
|
|
parse_math(p, os, FLAG_SIMPLE, MATH_MODE);
|
|
|
|
|
os << "\\]";
|
2003-04-23 15:14:43 +00:00
|
|
|
|
p.get_token(); // skip the second '$' token
|
2003-04-17 09:47:21 +00:00
|
|
|
|
} else {
|
|
|
|
|
// simple $...$ stuff
|
|
|
|
|
p.putback();
|
|
|
|
|
os << '$';
|
|
|
|
|
parse_math(p, os, FLAG_SIMPLE, MATH_MODE);
|
|
|
|
|
os << '$';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (flags & FLAG_SIMPLE) {
|
|
|
|
|
// this is the end of the formula
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else {
|
|
|
|
|
cerr << "\nmode: " << mode << endl;
|
|
|
|
|
p.error("something strange in the parser\n");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (t.cat() == catLetter ||
|
|
|
|
|
t.cat() == catSuper ||
|
|
|
|
|
t.cat() == catSub ||
|
|
|
|
|
t.cat() == catOther ||
|
|
|
|
|
t.cat() == catAlign ||
|
|
|
|
|
t.cat() == catActive ||
|
|
|
|
|
t.cat() == catParameter)
|
|
|
|
|
os << t.character();
|
|
|
|
|
|
|
|
|
|
else if (t.cat() == catBegin) {
|
|
|
|
|
os << '{';
|
|
|
|
|
parse_math(p, os, FLAG_BRACE_LAST, mode);
|
|
|
|
|
os << '}';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (t.cat() == catEnd) {
|
|
|
|
|
if (flags & FLAG_BRACE_LAST)
|
|
|
|
|
return;
|
|
|
|
|
os << "unexpected '}' in math\n";
|
|
|
|
|
}
|
|
|
|
|
|
2003-11-05 10:14:13 +00:00
|
|
|
|
else if (t.cat() == catComment) {
|
2003-11-19 10:35:50 +00:00
|
|
|
|
if (!t.cs().empty())
|
2003-11-05 10:14:13 +00:00
|
|
|
|
cerr << "Ignoring comment: " << t.asInput();
|
|
|
|
|
else
|
|
|
|
|
// "%\n" combination
|
|
|
|
|
p.skip_spaces();
|
|
|
|
|
}
|
2003-04-17 09:47:21 +00:00
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// control sequences
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
else if (t.cs() == "(") {
|
|
|
|
|
os << "\\(";
|
|
|
|
|
parse_math(p, os, FLAG_SIMPLE2, MATH_MODE);
|
|
|
|
|
os << "\\)";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (t.cs() == "[") {
|
2003-04-25 15:54:29 +00:00
|
|
|
|
// special handling of a few common SW user quirks
|
|
|
|
|
p.skip_spaces();
|
2003-09-09 18:27:24 +00:00
|
|
|
|
//if (p.next_token().cs() ==
|
2003-04-17 09:47:21 +00:00
|
|
|
|
os << "\\[";
|
|
|
|
|
parse_math(p, os, FLAG_EQUATION, MATH_MODE);
|
|
|
|
|
os << "\\]";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (t.cs() == "protect")
|
|
|
|
|
// ignore \\protect, will hopefully be re-added during output
|
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
else if (t.cs() == "begin") {
|
|
|
|
|
string const name = p.getArg('{', '}');
|
2003-04-23 15:14:43 +00:00
|
|
|
|
active_environments.push_back(name);
|
2003-04-17 09:47:21 +00:00
|
|
|
|
os << "\\begin{" << name << "}";
|
|
|
|
|
if (name == "tabular")
|
|
|
|
|
parse_math(p, os, FLAG_END, MATHTEXT_MODE);
|
|
|
|
|
else
|
|
|
|
|
parse_math(p, os, FLAG_END, mode);
|
|
|
|
|
os << "\\end{" << name << "}";
|
2003-10-23 11:46:33 +00:00
|
|
|
|
active_environments.pop_back();
|
2003-04-17 09:47:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (t.cs() == "end") {
|
|
|
|
|
if (flags & FLAG_END) {
|
|
|
|
|
// eat environment name
|
|
|
|
|
string const name = p.getArg('{', '}');
|
2003-04-23 15:14:43 +00:00
|
|
|
|
if (name != active_environment())
|
2003-04-17 09:47:21 +00:00
|
|
|
|
p.error("\\end{" + name + "} does not match \\begin{"
|
2003-04-23 15:14:43 +00:00
|
|
|
|
+ active_environment() + "}");
|
2003-04-17 09:47:21 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
p.error("found 'end' unexpectedly");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (t.cs() == ")") {
|
|
|
|
|
if (flags & FLAG_SIMPLE2)
|
|
|
|
|
return;
|
|
|
|
|
p.error("found '\\)' unexpectedly");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (t.cs() == "]") {
|
|
|
|
|
if (flags & FLAG_EQUATION)
|
|
|
|
|
return;
|
|
|
|
|
p.error("found '\\]' unexpectedly");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (t.cs() == "textrm" || t.cs() == "textsf" || t.cs() == "textbf"
|
2003-10-23 11:46:33 +00:00
|
|
|
|
|| t.cs() == "texttt" || t.cs() == "textsc"
|
|
|
|
|
|| t.cs() == "text" || t.cs() == "intertext") {
|
2003-04-17 09:47:21 +00:00
|
|
|
|
os << '\\' << t.cs() << '{';
|
|
|
|
|
parse_math(p, os, FLAG_ITEM, MATHTEXT_MODE);
|
|
|
|
|
os << '}';
|
|
|
|
|
}
|
|
|
|
|
|
2003-10-23 11:46:33 +00:00
|
|
|
|
else if (t.cs() == "mbox" || t.cs() == "fbox") {
|
|
|
|
|
os << "\\" << t.cs() << '{';
|
2003-04-17 09:47:21 +00:00
|
|
|
|
parse_math(p, os, FLAG_ITEM, MATHTEXT_MODE);
|
|
|
|
|
os << '}';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (t.cs() == "\"") {
|
2003-04-23 15:14:43 +00:00
|
|
|
|
string const name = p.verbatim_item();
|
2003-04-17 09:47:21 +00:00
|
|
|
|
if (name == "a") os << '<EFBFBD>';
|
|
|
|
|
else if (name == "o") os << '<EFBFBD>';
|
|
|
|
|
else if (name == "u") os << '<EFBFBD>';
|
|
|
|
|
else if (name == "A") os << '<EFBFBD>';
|
|
|
|
|
else if (name == "O") os << '<EFBFBD>';
|
|
|
|
|
else if (name == "U") os << '<EFBFBD>';
|
|
|
|
|
else os << "\"{" << name << "}";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (t.cs() == "ss")
|
|
|
|
|
os << "<EFBFBD>";
|
|
|
|
|
|
2003-09-09 18:27:24 +00:00
|
|
|
|
else
|
2003-04-17 09:47:21 +00:00
|
|
|
|
os << t.asInput();
|
|
|
|
|
|
|
|
|
|
if (flags & FLAG_LEAVE) {
|
|
|
|
|
flags &= ~FLAG_LEAVE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// }])
|