Back to index

texmacs  1.0.7.15
fromtex.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : fromtex.cpp
00004 * DESCRIPTION: conversion of tex strings into texmacs trees
00005 * COPYRIGHT  : (C) 1999  Joris van der Hoeven
00006 *******************************************************************************
00007 * This software falls under the GNU general public license version 3 or later.
00008 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
00009 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
00010 ******************************************************************************/
00011 
00012 #include "Tex/convert_tex.hpp"
00013 #include "scheme.hpp"
00014 #include "vars.hpp"
00015 #include "tree_correct.hpp"
00016 #include "url.hpp"
00017 
00018 tree upgrade_tex (tree t);
00019 bool textm_class_flag= false;
00020 //bool textm_class_flag= true;
00021 static bool textm_appendices= false;
00022 static bool textm_unicode   = false;
00023 static bool textm_natbib    = false;
00024 
00025 /*
00026 bool
00027 check_tree (tree t) {
00028   if (is_atomic (t)) {
00029     for (int i=0; i<N(t->label); i++)
00030       if (((int) t->label[i]) == 0) {
00031        cout << "t= " << t << "\n";
00032        return true;
00033       }
00034   }
00035   else {
00036     for (int i=0; i<N(t); i++)
00037       if (check_tree (t[i])) {
00038        if (is_atomic (t[i])) cout << "t= " << t << "\n";
00039        return true;
00040       }
00041   }
00042   return false;
00043 }
00044 */
00045 
00046 static bool
00047 is_var_compound (tree t, string s, int n) {
00048   return
00049     is_compound (t, s, n) ||
00050     (is_func (t, APPLY, n+1) && t[0] == s) ||
00051     (is_func (t, EXPAND, n+1) && t[0] == s);
00052 }
00053 
00054 /******************************************************************************
00055 * Preprocess preamble
00056 ******************************************************************************/
00057 
00058 tree
00059 filter_preamble (tree t) {
00060   int i, n=N(t);
00061   bool in_preamble= true;
00062   tree r (CONCAT);
00063   tree doc (CONCAT);
00064   tree preamble (CONCAT);
00065   tree title_info (CONCAT);
00066 
00067   for (i=0; i<n; i++) {
00068     tree u= t[i];
00069     if (is_tuple (u, "\\title") ||
00070         is_tuple (u, "\\author") ||
00071         is_tuple (u, "\\address"))
00072       title_info << u;
00073     else if (is_tuple (u, "\\affiliation")) {
00074       tree v= copy (u);
00075       v[0]= "\\address";
00076       title_info << v;
00077     }
00078     else if (is_tuple (u, "\\thanks")) {
00079       tree v= copy (u);
00080       v[0]= "\\title-thanks";
00081       title_info << v;
00082     }
00083     else if (is_tuple (u, "\\email")) {
00084       tree v= copy (u);
00085       v[0]= "\\title-email";
00086       title_info << v;
00087     }
00088     else if (is_tuple (u, "\\urladdr"))
00089       title_info << u;
00090     else if (is_tuple (u, "\\keywords"))
00091       title_info << u;
00092     else if (is_tuple (u, "\\classification"))
00093       title_info << u;
00094     else if (is_tuple (u, "\\subjclass"))
00095       title_info << u;
00096     else if (is_tuple (u, "\\subjclass*"))
00097       title_info << u;
00098     else if (in_preamble) {
00099       if (u == tuple ("\\begin-document")) {
00100        r << u;
00101        if (N(preamble) > 0)
00102          r << tuple ("\\begin-hide-preamble") << A(preamble)
00103            << tuple ("\\end-hide-preamble");
00104        in_preamble= false;
00105       }
00106       else if (is_tuple (u, "\\documentclass") ||
00107               is_tuple (u, "\\documentclass*") ||
00108               is_tuple (u, "\\documentstyle") ||
00109               is_tuple (u, "\\documentstyle*"))
00110        doc << u;
00111       else if (is_tuple (u, "\\def") ||
00112               is_tuple (u, "\\def*"))
00113        preamble << u << "\n" << "\n";
00114       else if (is_tuple (u, "\\newtheorem") ||
00115               is_tuple (u, "\\newtheorem*"))
00116        preamble << u << "\n" << "\n";
00117       else if (is_tuple (u, "\\newenvironment") ||
00118               is_tuple (u, "\\newenvironment*"))
00119        preamble << u << "\n" << "\n";
00120     }
00121     else doc << u;
00122   }
00123   r << A(title_info);
00124   r << A(doc);
00125   if (in_preamble) return t;
00126   return r;
00127 }
00128 
00129 /******************************************************************************
00130 * Transform parsed tex/latex trees into texmacs trees
00131 ******************************************************************************/
00132 
00133 #define l2e parsed_latex_to_tree
00134 #define t2e parsed_text_to_tree
00135 #define m2e latex_modifier_to_tree
00136 #define var_m2e var_latex_modifier_to_tree
00137 #define v2e latex_verbarg_to_string
00138 tree l2e (tree);
00139 tree latex_command_to_tree (tree t);
00140 
00141 tree
00142 latex_symbol_to_tree (string s) {
00143   if (s == "") return "";
00144   if (s[0] == '\\') {
00145     if (latex_type (s) == "command") {
00146       if (s == "\\ ") return " ";
00147       if (s == "\\-") return "";
00148       if (s == "\\/") return "";
00149       if (s == "\\AA") return "\xC5";
00150       if (s == "\\AE") return "\xC6";
00151       if (s == "\\DH") return "\xD0";
00152       if (s == "\\L") return "\x8A";
00153       if (s == "\\NG") return "\x8D";
00154       if (s == "\\O") return "\xD8";
00155       if (s == "\\OE") return "\xD7";
00156       if (s == "\\S") return "\x9F";
00157       if (s == "\\SS") return "\xDF";
00158       if (s == "\\TH") return "\xDE";
00159       if (s == "\\aa") return "\xE5";
00160       if (s == "\\ae") return "\xE6";
00161       if (s == "\\dh") return "\xF0";
00162       if (s == "\\dj") return "\x9E";
00163       if (s == "\\i") return "\x19";
00164       if (s == "\\j") return "\x1A";
00165       if (s == "\\l") return "\xAA";
00166       if (s == "\\ng") return "\xAD";
00167       if (s == "\\o") return "\xF8";
00168       if (s == "\\oe") return "\xF7";
00169       if (s == "\\ss") return "\xFF";
00170       if (s == "\\th") return "\xFE";
00171       if (s == "\\pounds") return "\xBF";
00172       if (s == "\\\\") return tree (FORMAT, "next line");
00173       if (s == "\\cr") return tree (FORMAT, "next line");
00174       if (s == "\\noindent")  return tree (FORMAT, "no first indentation");
00175       if (s == "\\linebreak")  return tree (FORMAT, "line break");
00176       if (s == "\\newline")  return tree (FORMAT, "new line");
00177       if (s == "\\nobreak")  return tree (FORMAT, "no line break");
00178       if (s == "\\nolinebreak")  return tree (FORMAT, "no line break");
00179       if (s == "\\pagebreak")  return tree (FORMAT, "page break");
00180       if (s == "\\nopagebreak")  return tree (FORMAT, "no page break after");
00181       if (s == "\\newpage")  return tree (FORMAT, "new page");
00182       if (s == "\\newdoublepage")  return tree (FORMAT, "new double page");
00183       if (s == "\\clearpage")  return tree (FORMAT, "new page");
00184       if (s == "\\cleardoublepage")  return tree (FORMAT, "new double page");
00185       if (s == "\\!")  return tree (SPACE, "-0.25spc");
00186       if (s == "\\,")  return tree (SPACE, "0.25spc");
00187       if (s == "\\:")  return tree (SPACE, "0.5spc");
00188       if (s == "\\;")  return tree (SPACE, "0.75spc");
00189       if (s == "\\*")  return "*";
00190       if (s == "\\|")  return "<||>";
00191       if (s == "\\quad")  return tree (SPACE, "1em");
00192       if (s == "\\qquad")  return tree (SPACE, "2em");
00193       if (s == "\\par")  return tree (VSPACE, "1fn");
00194       if (s == "\\smallskip")  return tree (VSPACE, "0.5fn");
00195       if (s == "\\medskip")  return tree (VSPACE, "1fn");
00196       if (s == "\\bigskip")  return tree (VSPACE, "2fn");
00197       if (s == "\\hfill")  return tree (HTAB, "1fn");
00198       if (s == "\\hline")  return tree (APPLY, "hline");
00199       if (s == "\\appendix") { textm_appendices= true; return ""; }
00200       if (s == "\\limits") return ""; // tree (FORMAT, "with limits");
00201       if (s == "\\nolimits") return ""; // temporarily
00202       if (s == "\\vert") return "|";
00203       if (s == "\\Vert") return "<||>";
00204       if (s == "\\notin") return "<nin>";
00205       if (s == "\\addots") return "<udots>";
00206       if (s == "\\dots") return "<ldots>";
00207       if (s == "\\infin") return "<infty>";
00208       if (s == "\\rang") return "<rangle>";
00209       if (s == "\\today") return compound ("date", "");
00210       if (s == "\\tableofcontents")
00211        return compound ("table-of-contents", "toc", tree (DOCUMENT, ""));
00212       if (s == "\\bgroup") return "";
00213       if (s == "\\egroup") return "";
00214       if (s == "\\colon") return ":";
00215       if (s == "\\dotsc") return "<ldots>";
00216       if (s == "\\dotsb") return "<cdots>";
00217       if (s == "\\dotsm") return "<cdots>";
00218       if (s == "\\dotsi") return "<cdots>";
00219       if (s == "\\dotso") return "<ldots>";
00220       if (s == "\\lvert") return "|";
00221       if (s == "\\rvert") return "|";
00222       if (s == "\\lVert") return "<||>";
00223       if (s == "\\rVert") return "<||>";
00224       if (s == "\\qed") return compound ("math", "<Box>");
00225       if (s == "\\implies") return "<Longrightarrow>";
00226       if (s == "\\iff") return "<Longleftrightarrow>";
00227       if (s == "\\gets") return "<leftarrow>";
00228     }
00229 
00230     if (latex_type (s) == "symbol") {
00231       if (s == "\\lnot") return "<neg>";
00232       if (s == "\\land") return "<wedge>";
00233       if (s == "\\lor") return "<vee>";
00234       return "<" * s(1,N(s)) * ">";
00235     }
00236 
00237     if (latex_type (s) == "texmacs") {
00238       if (s == "\\tmdummy")  return "";
00239     }
00240 
00241     if ((latex_type (s) == "modifier") && (latex_arity (s) == 0)) {
00242       s= s(1,N(s));
00243       if (s == "rmfamily") return tree (SET, FONT_FAMILY, "rm");
00244       if (s == "ttfamily") return tree (SET, FONT_FAMILY, "tt");
00245       if (s == "sffamily") return tree (SET, FONT_FAMILY, "sf");
00246       if (s == "mdseries") return tree (SET, FONT_SERIES, "medium");
00247       if (s == "bfseries") return tree (SET, FONT_SERIES, "bold");
00248       if (s == "upshape")  return tree (SET, FONT_SHAPE , "right");
00249       if (s == "itshape")  return tree (SET, FONT_SHAPE , "italic");
00250       if (s == "slshape")  return tree (SET, FONT_SHAPE , "slanted");
00251       if (s == "scshape")  return tree (SET, FONT_SHAPE , "small-caps");
00252 
00253       if (s == "cal")      return tree (SET, MATH_FONT  , "cal");
00254       if (s == "frak")     return tree (SET, MATH_FONT  , "Euler");
00255       if (s == "Bbb")      return tree (SET, MATH_FONT  , "Bbb*");
00256       if (s == "displaystyle") return tree (SET, MATH_DISPLAY, "true");
00257       if (s == "textstyle") return tree (SET, MATH_DISPLAY, "false");
00258       if (s == "scriptstyle") return tree (SET, MATH_LEVEL, "1");
00259       if (s == "scriptscriptstyle") return tree (SET, MATH_LEVEL, "2");
00260       if (s == "operatorname") return tree (SET, "dummy", "dummy");
00261       if (s == "boldsymbol") return tree (SET, MATH_FONT_SERIES, "bold");
00262 
00263       if (s == "rm") return tree (SET, FONT_FAMILY, "rm");
00264       if (s == "tt") return tree (SET, FONT_FAMILY, "tt");
00265       if (s == "sf") return tree (SET, FONT_FAMILY, "ss");
00266       if (s == "md") return tree (SET, FONT_SERIES, "right");
00267       if (s == "bf") return tree (SET, FONT_SERIES, "bold");
00268       if (s == "it") return tree (SET, FONT_SHAPE, "italic");
00269       if (s == "sl") return tree (SET, FONT_SHAPE, "slanted");
00270       if (s == "sc") return tree (SET, FONT_SHAPE, "small-caps");
00271       if (s == "em") {
00272        if (command_type ["!em"] == "false") {
00273          command_type ("!em")= "true";
00274          return tree (SET, FONT_SHAPE, "italic");
00275        }
00276        else {
00277          command_type ("!em")= "false";
00278          return tree (SET, FONT_SHAPE, "right");
00279        }
00280       }
00281 
00282       if (s == "tiny") return tree (SET, FONT_SIZE, "0.59");
00283       if (s == "scriptsize") return tree (SET, FONT_SIZE, "0.71");
00284       if (s == "footnotesize") return tree (SET, FONT_SIZE, "0.71");
00285       if (s == "small") return tree (SET, FONT_SIZE, "0.84");
00286       if (s == "normalsize") return tree (SET, FONT_SIZE, "1");
00287       if (s == "large") return tree (SET, FONT_SIZE, "1.19");
00288       if (s == "Large") return tree (SET, FONT_SIZE, "1.41");
00289       if (s == "LARGE") return tree (SET, FONT_SIZE, "1.41");
00290       if (s == "huge") return tree (SET, FONT_SIZE, "1.68");
00291       if (s == "Huge") return tree (SET, FONT_SIZE, "2");
00292       
00293       if (s == "black") return tree (SET, COLOR, "black");
00294       if (s == "white") return tree (SET, COLOR, "white");
00295       if (s == "grey") return tree (SET, COLOR, "grey");
00296       if (s == "red") return tree (SET, COLOR, "red");
00297       if (s == "blue") return tree (SET, COLOR, "blue");
00298       if (s == "yellow") return tree (SET, COLOR, "yellow");
00299       if (s == "green") return tree (SET, COLOR, "green");
00300       if (s == "orange") return tree (SET, COLOR, "orange");
00301       if (s == "magenta") return tree (SET, COLOR, "magenta");
00302       if (s == "brown") return tree (SET, COLOR, "brown");
00303       if (s == "pink") return tree (SET, COLOR, "pink");
00304 
00305       cerr << "The symbol was " << s << "\n";
00306       FAILED ("unexpected situation");
00307     }
00308     if (latex_type (s) == "operator")
00309       return s(1,N(s));
00310     if (latex_type (s) == "control") return s(1,N(s));
00311     if ((s == "\\ldots") && (command_type ("!mode") != "math")) return "...";
00312     if (s == "\\bignone") return tree (BIG, ".");
00313     if (latex_type (s) == "big-symbol") {
00314       if (s(0,4)=="\\big") return tree (BIG, s(4,N(s)));
00315       else return tree (BIG, s(1,N(s)));
00316     }
00317 
00318     if ((N(s) > 7) && (s(0,7) == "\\begin-"))
00319       return tree (BEGIN, s(7,N(s)));
00320     if ((N(s) > 5) && (s(0,5) == "\\end-"))
00321       return tree (END, s(5,N(s)));
00322 
00323     if (starts (s, "\\#") && s != "\\#") {
00324       textm_unicode= true;
00325       return "<" * s (1, N(s)) * ">";
00326     }
00327     return tree (APPLY, s(1,N(s)));
00328   }
00329   if ((N(s) == 2) && (s[0] == '#') && (s[1] >= '0') && (s[1] <= '9'))
00330     return tree (APPLY, s(1,2));
00331   if (s == "&") return tree (FORMAT, "line separator");
00332   return copy (s);
00333 }
00334 
00335 tree
00336 t2e (tree t, bool flag= true) {
00337   string old_mode= command_type ["!mode"];
00338   command_type ("!mode") = "text";
00339   tree r= l2e (t);
00340   command_type ("!mode") = old_mode;
00341   while (flag && (arity(r)>0)) r= r[0];
00342   return r;
00343 }
00344 
00345 bool
00346 test_alpha_on_end (tree t) {
00347   if (is_atomic (t) && (N(t->label) >= 1))
00348     return is_alpha (t->label[N(t->label)-1]);
00349   if (is_concat (t) && (N(t)>=1))
00350     return test_alpha_on_end (t[N(t)-1]);
00351   return false;
00352 }
00353 
00354 string
00355 string_arg (tree t) {
00356   if (is_atomic (t)) return t->label;
00357   else if (is_concat (t)) {
00358     string r;
00359     int i, n= N(t);
00360     for (i=0; i<n; i++)
00361       r << string_arg (t[i]);
00362     return r;
00363   }
00364   else if (is_func (t, RSUB, 1))
00365     return "_" * string_arg (t[0]);
00366   else if (is_func (t, RSUP, 1))
00367     return "^" * string_arg (t[0]);
00368   else if (is_func (t, APPLY, 1) && t[0] == "nbsp")
00369     return " ";
00370   else {
00371     //cout << "t= " << t << "\n";
00372     return "";
00373   }
00374 }
00375 
00376 tree
00377 latex_concat_to_tree (tree t, bool& new_flag) {
00378   int i, n=N(t);
00379   tree r (CONCAT), env (CONCAT);
00380 
00381   if ((n > 0) && (command_type ["!mode"] == "math") &&
00382       (is_tuple (t[0], "\\rm", 0) || is_tuple (t[0], "\\tt", 0)))
00383     {
00384       command_type ("!mode") = "text";
00385       tree u= latex_concat_to_tree (t, new_flag);
00386       command_type ("!mode") = "math";
00387       return tree (CONCAT, tree (SET, MODE, "text"), u, tree (RESET, MODE));
00388     }
00389 
00390   command_type ->extend ();
00391   command_arity->extend ();
00392   command_def  ->extend ();
00393 
00394   for (i=0; i<n; i++) {
00395     if (is_tuple (t[i]) && (N(t[i])==1)) {
00396       string s= t[i][0]->label;
00397       if (latex_type (s) == "math-environment") {
00398        if (s(0,4)=="\\end") command_type ("!mode") = "text";
00399        else command_type ("!mode") = "math";
00400       }
00401       if (s == "\\begin-verbatim") command_type ("!verbatim") = "true";
00402       else if (s == "\\end-verbatim") command_type ("!verbatim") = "false";
00403     }
00404     if (is_atomic (t[i]) && (command_type["!verbatim"] == "true")) {
00405       r << tm_encode (t[i]->label);
00406       continue;
00407     }
00408 
00409     bool operator_flag=
00410       is_tuple (t[i]) && (N(t[i])==1) &&
00411       (latex_type (t[i][0]->label) == "operator");
00412     bool cc_flag= is_concat (t[i]);
00413     tree u= (cc_flag? latex_concat_to_tree (t[i], new_flag): l2e (t[i]));
00414     if (is_atomic (u)) {
00415       if (u == " ") {
00416        if (command_type ["!mode"] == "math") {
00417          if ((i==0) || (!is_tuple (t[i-1])) || (N(t[i-1])!=1) ||
00418              (latex_type (t[i-1][0]->label) != "operator"))
00419            continue;
00420        }
00421        else {
00422          if ((t[i] != tree (TUPLE, "\\ "))) {
00423            if (i>0 && is_tuple (t[i-1])) {
00424              string s= t[i-1][0]->label;
00425              if ((s[0] == '\\') && (latex_type (s) == "command") &&
00426                 (s!="\\end-math") && (s!="\\end-displaymath"))
00427               if ((arity(t[i-1])==1) || (s=="\\label")) continue;
00428              if (starts (s, "\\begin-") &&
00429                 (command_type["!verbatim"] != "true"))
00430               continue;
00431            }
00432            if (i+1<N(t) && is_tuple (t[i+1])) {
00433              string s= t[i+1][0]->label;
00434              if (starts (s, "\\end-") &&
00435                 (command_type["!verbatim"] != "true"))
00436               continue;
00437            }
00438          }
00439        }
00440       }
00441 
00442       string s= u->label;
00443       bool old_flag= new_flag;
00444       if (!cc_flag) new_flag= ((N(s)==1) && is_alpha(s));
00445       if ((command_type ["!mode"] == "math") &&
00446          (!cc_flag) && old_flag && (new_flag || operator_flag)) s= "*" * s;
00447       if ((N(r)>0) && is_atomic (r[N(r)-1])) r[N(r)-1]->label << s;
00448       else r << s;
00449     }
00450     else {
00451       if (is_func (u, SET, 2)) {
00452        env << u;
00453        if (((i+1)<n) && (t[i+1]==tree(" "))) i++;
00454       }
00455       r << u;
00456       if (!cc_flag) new_flag= false;
00457     }
00458   }
00459   
00460   for (i=N(env)-1; i>=0; i--)
00461     r << tree (RESET, copy (env[i][0]));
00462 
00463   command_type ->shorten ();
00464   command_arity->shorten ();
00465   command_def  ->shorten ();
00466 
00467   if (N(r)==0) return "";
00468   if (N(r)==1) return r[0];
00469   return r;
00470 }
00471 
00472 tree
00473 m2e (tree t, string var, string val) {
00474   return tree (CONCAT,
00475               tree (SET, copy (var), copy (val)),
00476               l2e (t[1]),
00477               tree (RESET, copy (var)));
00478 }
00479 
00480 tree
00481 var_m2e (tree t, string var, string val) {
00482   return tree (CONCAT,
00483               tree (SET, copy (var), copy (val)),
00484               t2e (t[1], false),
00485               tree (RESET, copy (var)));
00486 }
00487 
00488 string
00489 v2e (tree t) {
00490   return string_arg (t2e (t, false));
00491 }
00492 
00493 static bool
00494 is_left_type (tree t) {
00495   if (is_compound (t)) return false;
00496   string s= t->label;
00497   return
00498     (s == "(") || (s == "[") || (s == "\\{") ||
00499     (s == "\\lfloor") || (s == "\\lceil") || (s == "\\langle");
00500 }
00501 
00502 static bool
00503 is_right_type (tree t) {
00504   if (is_compound (t)) return false;
00505   string s= t->label;
00506   return (s == ")") || (s == "]") || (s == "\\}") ||
00507     (s == "\\rfloor") || (s == "\\rceil") || (s == "\\rangle");
00508 }
00509 
00510 static bool
00511 is_large_delimiter (tree t, int& type) {
00512   if ((!is_tuple (t)) || (N(t) != 2) ||
00513       is_compound (t[0]) || is_compound (t[1])) return false;
00514   string s= t[0]->label;
00515   if (starts (s, "\\Big")) s= "\\big" * s(4,N(s));
00516   if (starts (s, "\\bigg")) s= "\\big" * s(5,N(s));
00517   if ((s == "\\left") || (s == "\\bigl") ||
00518       ((s == "\\big") && is_left_type (t[1]))) {
00519     type= -1;
00520     return true;
00521   }
00522   if ((s == "\\right") || (s == "\\bigr") ||
00523       ((s == "\\big") && is_right_type (t[1]))) {
00524     type= 1;
00525     return true;
00526   }
00527   if (s == "\\bigm") {
00528     type= 0;
00529     return true;
00530   }
00531   return false;
00532 }
00533 
00534 tree
00535 latex_cite_to_tree (string cite_type, string s) {
00536   tree r (APPLY, cite_type);
00537   int i, last, n=N(s);
00538   for (last=0, i=0; i<n; i++) {
00539     while ((i<n) && (s[i]!=',')) i++;
00540     r << s (last, i);
00541     if (i<n) i++;
00542     while ((i<n) && (s[i]==' ')) i++;
00543     last= i;
00544   }
00545   if (N(r) == 1) return "";
00546   return r;
00547 }
00548 
00549 tree
00550 latex_index_to_tree (string s) {
00551   int i, start, n= N(s);
00552   array<tree> a (0);
00553   for (start= i= 0; i<n; i++)
00554     if (s[i] == '!' && N(a) < 3) {
00555       a << tree (s (start, i));
00556       start= i+1;
00557     }
00558   a << tree (s (start, i));
00559   if (N(a) == 1) return compound ("index", a);
00560   if (N(a) == 2) return compound ("subindex", a);
00561   if (N(a) == 3) return compound ("subsubindex", a);
00562   return compound ("subsubsubindex", a);
00563 }
00564 
00565 tree
00566 latex_accent (tree t, string acc) {
00567   return tree (WITH, MODE, "math",
00568               tree (WIDE, tree (WITH, MODE, "text", l2e (t)), acc));
00569 }
00570 
00571 tree
00572 latex_eps_get (tree t, string var) {
00573   if (!is_atomic (t)) return "";
00574   string s= t->label;
00575   int start=0, i, n=N(s);
00576   for (i=0; i <= n; i++)
00577     if (i == n || s[i] == ',') {
00578       string ss= s (start, i);
00579       while (starts (ss, " ")) ss= ss (1, N(ss));
00580       while (ends (ss, " ")) ss= ss (0, N(ss) - 1);
00581       int j, k= N(ss);
00582       for (j=0; j<k; j++)
00583        if (ss[j] == '=') break;
00584       string v= ss (0, j);
00585       while (ends (v, " ")) v= v (0, N(v) - 1);
00586       if (j < k && v == var) {
00587        string val= ss (j+1, N(ss));
00588        while (starts (val, " ")) val= val (1, N(val));
00589        return val;
00590       }
00591       start= i+1;
00592     }
00593   return "";
00594 }
00595 
00596 tree
00597 latex_command_to_tree (tree t) {
00598   if (is_tuple (t, "\\def", 2)) {
00599     string var= string_arg (t[1]);
00600     if ((N(var)>0) && (var[0]=='\\')) var= var (1, N(var));
00601     return tree (ASSIGN, var, tree (FUNC, l2e (t[2])));
00602   }
00603   if (is_tuple (t, "\\def*", 3)) {
00604     string var= string_arg (t[1]);
00605     if ((N(var)>0) && (var[0]=='\\')) var= var (1, N(var));
00606     int i, arity= as_int (l2e(t[2]));
00607     tree f (FUNC);
00608     for (i=1; i<=arity; i++) f << as_string (i);
00609     f << l2e (t[3]);
00610     return tree (ASSIGN, var, f);
00611   }
00612 
00613   if (is_tuple (t, "\\newtheorem", 2) || is_tuple (t, "\\newtheorem*", 2)) {
00614     string var= l2e(t[1])->label;
00615     string val= l2e(t[2])->label;
00616     return compound ("new-theorem", var, val);
00617   }
00618 
00619   if (is_tuple (t, "\\newenvironment", 3)) {
00620     string var= l2e(t[1])->label;
00621     return tree (ASSIGN, var, tree (ENV, l2e (t[2]), l2e (t[3])));
00622   }
00623   if (is_tuple (t, "\\newenvironment*", 4)) {
00624     string var= l2e(t[1])->label;
00625     int i, arity= as_int (l2e(t[2])->label);
00626     tree e (ENV);
00627     for (i=1; i<=arity; i++) e << as_string (i);
00628     e << l2e (t[3]);
00629     e << l2e (t[4]);
00630     return tree (ASSIGN, var, e);
00631   }
00632 
00633   if (is_tuple (t, "\\arabic", 1)) {
00634     tree u= l2e (t[1]);
00635     if (is_compound (u)) return "";
00636     return tree (APPLY, u->label * "nr");
00637   }
00638   if (is_tuple (t, "\\equal", 2))
00639     return tree (EQUAL, l2e (t[1]), l2e (t[2]));
00640   if (is_tuple (t, "\\ifthenelse", 3))
00641     return tree (IF, l2e (t[1]), l2e (t[2]), l2e (t[3]));
00642 
00643   if (textm_appendices && is_tuple (t, "\\chapter", 1))
00644     return tree (APPLY, "appendix", l2e (t[1]));
00645 
00646   if (is_tuple (t, "\\^", 1)) return latex_accent (t[1], "^");
00647   if (is_tuple (t, "\\~", 1)) return latex_accent (t[1], "~");
00648   if (is_tuple (t, "\\`", 1)) return latex_accent (t[1], "<grave>");
00649   if (is_tuple (t, "\\'", 1)) return latex_accent (t[1], "<acute>");
00650   if (is_tuple (t, "\\\"", 1)) return latex_accent (t[1], "<ddot>"); // diaeresis
00651   if (is_tuple (t, "\\.", 1)) return latex_accent (t[1], "<dot>");
00652   if (is_tuple (t, "\\u", 1)) return latex_accent (t[1], "<breve>");
00653   if (is_tuple (t, "\\v", 1)) return latex_accent (t[1], "<check>"); // caron
00654   if (is_tuple (t, "\\=", 1)) return latex_accent (t[1], "<bar>");   // macron
00655 
00656 
00657   if (is_tuple (t, "\\textrm", 1)) return m2e (t, FONT_FAMILY, "rm");
00658   if (is_tuple (t, "\\texttt", 1)) return m2e (t, FONT_FAMILY, "tt");
00659   if (is_tuple (t, "\\textsf", 1)) return m2e (t, FONT_FAMILY, "ss");
00660   if (is_tuple (t, "\\textmd", 1)) return m2e (t, FONT_SERIES, "medium");
00661   if (is_tuple (t, "\\textbf", 1)) return m2e (t, FONT_SERIES, "bold");
00662   if (is_tuple (t, "\\textup", 1)) return m2e (t, FONT_SHAPE, "right");
00663   if (is_tuple (t, "\\textit", 1)) return m2e (t, FONT_SHAPE, "italic");
00664   if (is_tuple (t, "\\textsl", 1)) return m2e (t, FONT_SHAPE, "slanted");
00665   if (is_tuple (t, "\\textsc", 1)) return m2e (t, FONT_SHAPE, "small-caps");
00666   if (is_tuple (t, "\\tmrsub", 1)) return tree (RSUB, l2e (t[1]));
00667   if (is_tuple (t, "\\tmrsup", 1)) return tree (RSUP, l2e (t[1]));
00668   if (is_tuple (t, "\\textsubscript", 1)) return tree (RSUB, l2e (t[1]));
00669   if (is_tuple (t, "\\textsuperscript", 1)) return tree (RSUP, l2e (t[1]));
00670   if (is_tuple (t, "\\tmtextrm", 1)) return m2e (t, FONT_FAMILY, "rm");
00671   if (is_tuple (t, "\\tmtexttt", 1)) return m2e (t, FONT_FAMILY, "tt");
00672   if (is_tuple (t, "\\tmtextsf", 1)) return m2e (t, FONT_FAMILY, "ss");
00673   if (is_tuple (t, "\\tmtextmd", 1)) return m2e (t, FONT_SERIES, "medium");
00674   if (is_tuple (t, "\\tmtextbf", 1)) return m2e (t, FONT_SERIES, "bold");
00675   if (is_tuple (t, "\\tmtextup", 1)) return m2e (t, FONT_SHAPE, "right");
00676   if (is_tuple (t, "\\tmtextit", 1)) return m2e (t, FONT_SHAPE, "italic");
00677   if (is_tuple (t, "\\tmtextsl", 1)) return m2e (t, FONT_SHAPE, "slanted");
00678   if (is_tuple (t, "\\tmtextsc", 1)) return m2e (t, FONT_SHAPE, "small-caps");
00679   if (is_tuple (t, "\\emph", 1))   return m2e (t, FONT_SHAPE, "italic");
00680   if (is_tuple (t, "\\operatorname", 1))
00681     return var_m2e (t, MATH_FONT_FAMILY, "rm");
00682   if (is_tuple (t, "\\boldsymbol", 1))
00683     return var_m2e (t, MATH_FONT_SERIES, "bold");
00684   if (is_tuple (t, "\\mathnormal", 1)) return m2e (t, MATH_FONT_FAMILY, "mr");
00685   if (is_tuple (t, "\\mathrm", 1)) return var_m2e (t, MATH_FONT_FAMILY, "rm");
00686   if (is_tuple (t, "\\mathtt", 1)) return var_m2e (t, MATH_FONT_FAMILY, "tt");
00687   if (is_tuple (t, "\\mathsf", 1)) return var_m2e (t, MATH_FONT_FAMILY, "ss");
00688   if (is_tuple (t, "\\mathbf", 1)) return var_m2e (t, MATH_FONT_FAMILY, "bf");
00689   if (is_tuple (t, "\\mathit", 1)) return var_m2e (t, MATH_FONT_FAMILY, "it");
00690   if (is_tuple (t, "\\mathsl", 1)) return var_m2e (t, MATH_FONT_FAMILY, "sl");
00691   if (is_tuple (t, "\\mathup", 1)) return var_m2e (t, MATH_FONT_FAMILY, "up");
00692   if (is_tuple (t, "\\mathcal", 1)) return m2e (t, MATH_FONT, "cal");
00693   if (is_tuple (t, "\\mathfrak", 1)) return m2e (t, MATH_FONT, "Euler");
00694   if (is_tuple (t, "\\mathbb", 1)) return m2e (t, MATH_FONT, "Bbb");
00695   if (is_tuple (t, "\\mathbbm", 1)) return m2e (t, MATH_FONT, "Bbb*");
00696   if (is_tuple (t, "\\mathscr", 1)) return m2e (t, MATH_FONT, "cal*");
00697 
00698   if (is_tuple (t, "\\prime", 1)) return tree (RPRIME, string_arg (t[1]));
00699   if (is_tuple (t, "\\frac", 2)) return tree (FRAC, l2e (t[1]), l2e (t[2]));
00700   if (is_tuple (t, "\\atop", 2))
00701     return compound ("atop", l2e (t[1]), l2e (t[2]));
00702   if (is_tuple (t, "\\sqrt", 1))  return tree (SQRT, l2e (t[1]));
00703   if (is_tuple (t, "\\sqrt*", 2)) return tree (SQRT, l2e (t[2]), l2e (t[1]));
00704   if (is_tuple (t, "\\<sub>", 1)) return tree (RSUB, l2e (t[1]));
00705   if (is_tuple (t, "\\not", 1)) return tree (NEG, l2e (t[1]));
00706   if (is_tuple (t, "\\bar", 1)) return tree (WIDE, l2e (t[1]), "<bar>");
00707   if (is_tuple (t, "\\overline", 1))
00708     return tree (WIDE, l2e (t[1]), "<bar>");
00709   if (is_tuple (t, "\\underline", 1))
00710     return tree (VAR_WIDE, l2e (t[1]), "<bar>");
00711   if (is_tuple (t, "\\hat", 1)) return tree (WIDE, l2e (t[1]), "^");
00712   if (is_tuple (t, "\\tilde", 1)) return tree (WIDE, l2e (t[1]), "~");
00713   if (is_tuple (t, "\\widehat", 1)) return tree (WIDE, l2e (t[1]), "^");
00714   if (is_tuple (t, "\\widetilde", 1)) return tree (WIDE, l2e (t[1]), "~");
00715   if (is_tuple (t, "\\dot", 1)) return tree (WIDE, l2e (t[1]), "<dot>");
00716   if (is_tuple (t, "\\ddot", 1)) return tree (WIDE, l2e (t[1]), "<ddot>");
00717   if (is_tuple (t, "\\dddot", 1)) return tree (WIDE, l2e (t[1]), "<dddot>");
00718   if (is_tuple (t, "\\ddddot", 1)) return tree (WIDE, l2e (t[1]), "<ddddot>");
00719   if (is_tuple (t, "\\check", 1)) return tree (WIDE, l2e (t[1]), "<check>");
00720   if (is_tuple (t, "\\grave", 1)) return tree (WIDE, l2e (t[1]), "<grave>");
00721   if (is_tuple (t, "\\acute", 1)) return tree (WIDE, l2e (t[1]), "<acute>");
00722   if (is_tuple (t, "\\vec", 1)) return tree (WIDE, l2e (t[1]), "<vect>");
00723   if (is_tuple (t, "\\breve", 1)) return tree (WIDE, l2e (t[1]), "<breve>");
00724   if (is_tuple (t, "\\abovering", 1) || is_tuple (t, "\\mathring", 1))
00725     return tree (WIDE, l2e (t[1]), "<abovering>");
00726   if (is_tuple (t, "\\hspace", 1) || is_tuple (t, "\\hspace*", 1)) {
00727     tree r= t2e (t[1]);
00728     if (is_var_compound (r, "fill", 0)) return tree (HTAB, "1fn");
00729     return tree (SPACE, r);
00730   }
00731   if (is_tuple (t, "\\vspace", 1) || is_tuple (t, "\\vspace*", 1))
00732     return tree (VSPACE, t2e (t[1]));
00733   if (is_tuple (t, "\\label", 1)) return tree (LABEL, t2e (t[1]));
00734   if (is_tuple (t, "\\ref", 1)) return tree (REFERENCE, t2e (t[1]));
00735   if (is_tuple (t, "\\newcounter", 1))
00736     return compound ("new-counter", v2e (t[1]));
00737   if (is_tuple (t, "\\value", 1))
00738     return compound ("value-counter", v2e (t[1]));
00739   if (is_tuple (t, "\\stepcounter", 1))
00740     return compound ("inc-counter", v2e (t[1]));
00741   if (is_tuple (t, "\\refstepcounter", 1))
00742     return compound ("next-counter", v2e (t[1]));
00743   if (is_tuple (t, "\\setcounter", 2)) // FIXME: only reset works
00744     return compound ("reset-counter", v2e (t[1]));
00745   if (is_tuple (t, "\\addtocounter", 2)) // FIXME: only inc works
00746     return compound ("inc-counter", v2e (t[1]));
00747   if (is_tuple (t, "\\setlength", 2)) {
00748     if (!textm_class_flag) return "";
00749     else {
00750       string len= (is_atomic (t[1])? t[1]->label: v2e (t[1]));
00751       tree val= l2e (t[2]);
00752       if (len == "\\oddsidemargin") len= "tex-odd-side-margin";
00753       if (len == "\\evensidemargin") len= "tex-even-side-margin";
00754       if (len == "\\textwidth") len= "tex-text-width";
00755       if (len == "\\topmargin") len= "tex-top-margin";
00756       if (len == "\\headheight") len= "tex-head-height";
00757       if (len == "\\headsep") len= "tex-head-sep";
00758       if (len == "\\topskip") len= "tex-top-skip";
00759       if (len == "\\textheight") len= "tex-text-height";
00760       if (len == "\\footskip") len= "tex-foot-skip";
00761       if (len == "\\footnotesep") len= "tex-footnote-sep";
00762       if (len == "\\columnsep") len= "tex-column-sep";
00763       if (len == "\\marginparwidth") len= "tex-margin-par-width";
00764       if (len == "\\par-indent") len= "par-first";
00765       if (len == "\\jot") len= "tex-jot";
00766       if (len == "\\mathindent") len= "tex-math-indent";
00767       if (len == "\\abovedisplayskip") len= "tex-above-display-skip";
00768       if (len == "\\belowdisplayskip") len= "tex-below-display-skip";
00769       if (len == "\\abovedisplayshortskip")
00770        len= "tex-above-display-short-skip";
00771       if (len == "\\belowdisplayshortskip")
00772        len= "tex-below-display-short-skip";
00773       return tree (ASSIGN, len, tree (MACRO, val));
00774     }
00775   }
00776   if (is_tuple (t, "\\addtolength")) return "";
00777   if (is_tuple (t, "\\enlargethispage")) return "";
00778   if (is_tuple (t, "\\mathop", 1)) return l2e (t[1]);
00779   if (is_tuple (t, "\\mathrel", 1)) return l2e (t[1]);
00780   if (is_tuple (t, "\\overbrace", 1))
00781     return tree (WIDE, l2e (t[1]), "<wide-overbrace>");
00782   if (is_tuple (t, "\\underbrace", 1))
00783     return tree (VAR_WIDE, l2e (t[1]), "<wide-underbrace>");
00784 
00785   if (is_tuple (t, "\\text", 1) ||
00786       is_tuple (t, "\\mbox", 1) || is_tuple (t, "\\hbox", 1))
00787     return var_m2e (t, MODE, "text");
00788   if (is_tuple (t, "\\ensuremath", 1))
00789     return var_m2e (t, MODE, "math");
00790   if (is_tuple (t, "\\Mvariable", 1))
00791     return compound ("Mvariable", var_m2e (t, MODE, "text"));
00792   if (is_tuple (t, "\\Mfunction", 1))
00793     return compound ("Mfunction", var_m2e (t, MODE, "text"));
00794   if (is_tuple (t, "\\Muserfunction", 1))
00795     return compound ("Muserfunction", var_m2e (t, MODE, "text"));
00796 
00797   if (is_tuple (t, "\\<sup>", 1)) {
00798     if (is_tuple (t[1], "\\prime", 0))
00799       return tree (RPRIME, "'");
00800     else return tree (RSUP, l2e (t[1]));
00801   }
00802   if (is_tuple (t, "\\stackrel", 2))
00803     return tree (ABOVE, l2e (t[2]), l2e (t[1]));
00804   if (is_tuple (t, "\\overset", 2))
00805     return tree (ABOVE, l2e (t[2]), l2e (t[1]));
00806   if (is_tuple (t, "\\underset", 2))
00807     return tree (BELOW, l2e (t[2]), l2e (t[1]));
00808   if (is_tuple (t, "\\parbox", 2))
00809     return compound ("mini-paragraph", v2e (t[1]), l2e (t[2]));
00810   if (is_tuple (t, "\\parbox*", 3))
00811     return compound ("mini-paragraph", v2e (t[2]), l2e (t[3]));
00812 
00813   int dtype= 0;
00814   if (is_large_delimiter (t, dtype)) {
00815     string s= t[1]->label;
00816     if ((N(s)>1) && (s[0]=='\\')) s=s(1,N(s));
00817     if (s == "vert") s= "|";
00818     if (s == "Vert") s= "||";
00819     if (dtype == -1) return tree (LEFT, s);
00820     else if (dtype == 1) return tree (RIGHT, s);
00821     else return tree (MID, s);
00822   }
00823   if (is_tuple (t, "\\cite", 1) || is_tuple (t, "\\nocite", 1)) {
00824     string cite_type= t[0]->label (1, N(t[0]->label));
00825     string s= v2e (t[1]);
00826     return latex_cite_to_tree (cite_type, s);
00827   }
00828   if (is_tuple (t, "\\cite*", 2)) {
00829     tree   ot= l2e (t[1]);
00830     string s = v2e (t[2]);
00831     tree   ct= latex_cite_to_tree ("cite", s);
00832     if (N(ct) == 2) return compound ("cite-detail", ct[1], ot);
00833     return tree (CONCAT, ct, " (", ot, ")");
00834   }
00835   if (is_tuple (t, "\\citedetail", 2))
00836     return compound ("cite-detail", l2e (t[1]), l2e (t[2]));
00837   if (is_tuple (t, "\\citet", 1) || is_tuple (t, "\\citep", 1) ||
00838       is_tuple (t, "\\citet*", 1) || is_tuple (t, "\\citep*", 1) ||
00839       is_tuple (t, "\\citealt", 1) || is_tuple (t, "\\citealp", 1) ||
00840       is_tuple (t, "\\citealt*", 1) || is_tuple (t, "\\citealp*", 1))
00841     {
00842       textm_natbib= true;
00843       string star= "";
00844       string cite_type= t[0]->label (1, N(t[0]->label));
00845       if (ends (cite_type, "*")) {
00846        star= "*"; cite_type= cite_type (0, N (cite_type) - 1); }
00847       if (cite_type == "citet") cite_type= "cite-textual" * star;
00848       if (cite_type == "citep") cite_type= "cite-parenthesized" * star;
00849       if (cite_type == "citealt") cite_type= "cite-raw" * star;
00850       if (cite_type == "citealp") cite_type= "cite-raw" * star;
00851       string s= v2e (t[1]);
00852       return latex_cite_to_tree (cite_type, s);
00853     }
00854   if (is_tuple (t, "\\citetext", 1))
00855     return compound ("render-cite", l2e (t[1]));
00856   if (is_tuple (t, "\\citeauthor", 1)) {
00857     textm_natbib= true; return compound ("cite-author-link", t2e (t[1])); }
00858   if (is_tuple (t, "\\citeauthor*", 1)) {
00859     textm_natbib= true; return compound ("cite-author*-link", t2e (t[1])); }
00860   if (is_tuple (t, "\\citeyear", 1)) {
00861     textm_natbib= true; return compound ("cite-year-link", t2e (t[1])); }
00862   if (is_tuple (t, "\\bibitem", 1))
00863     return compound ("bibitem", v2e (t[1]));
00864   if (is_tuple (t, "\\bibitem*", 2))
00865     return compound ("bibitem*", v2e (t[1]), v2e (t[2]));
00866   if (is_tuple (t, "\\index", 1)) {
00867     string s= v2e (t[1]);
00868     return latex_index_to_tree (s);
00869   }
00870   if (is_tuple (t, "\\displaylines", 1)) {
00871     tree u= l2e (t[1]);
00872     return tree (CONCAT, tree (BEGIN, "matrix"), u, tree (END, "matrix"));
00873   }
00874   if (is_tuple (t, "\\cases", 1)) {
00875     tree u= l2e (t[1]);
00876     tree r= tree (CONCAT);
00877     r << tree (LEFT, "\{") << tree (BEGIN, "array", "lll") << u
00878       << tree (END, "array") << tree (RIGHT, ".");
00879     return r;
00880   }
00881   if (is_tuple (t, "\\includegraphics", 1) ||
00882       is_tuple (t, "\\includegraphics*", 1)) {
00883     tree name= v2e (t[1]);
00884     if (name == "") return "";
00885     else {
00886       tree g (IMAGE, 7);
00887       g[0]= name;
00888       return g;
00889     }
00890   }
00891   if (is_tuple (t, "\\includegraphics*", 2) ||
00892       is_tuple (t, "\\includegraphics**", 2)) {
00893     tree name= v2e (t[2]);
00894     tree data= v2e (t[1]);
00895     if (data == "" || name == "") return "";
00896     else {
00897       tree g (IMAGE, 7);
00898       g[0]= name;
00899       tree width = latex_eps_get (data, "width");
00900       tree height= latex_eps_get (data, "height");
00901       g[1]= width;
00902       g[2]= height;
00903       return g;
00904     }
00905   }
00906   if (is_tuple (t, "\\epsfig", 1)) {
00907     tree data  = v2e (t[1]);
00908     tree name  = latex_eps_get (data, "file");
00909     tree width = latex_eps_get (data, "width");
00910     tree height= latex_eps_get (data, "height");
00911     if (name == "") return "";
00912     else {
00913       tree g (IMAGE, 5);
00914       g[0]= name;
00915       g[1]= width;
00916       g[2]= height;
00917       return g;
00918 
00919     }
00920   }
00921   if (is_tuple (t, "\\fbox", 1)) return compound ("frame", l2e (t[1]));
00922   if (is_tuple (t, "\\framebox", 1)) return compound ("frame", l2e (t[1]));
00923   if (is_tuple (t, "\\centerline", 1)) return compound ("center", l2e (t[1]));
00924   if (is_tuple (t, "\\noalign", 1))
00925     return ""; // FIXME: for larger space in maple matrices
00926   if (is_tuple (t, "\\etalchar", 1)) return t2e (t[1]);
00927   if (is_tuple (t, "\\natexlab", 1)) return t2e (t[1]);
00928   if (is_tuple (t, "\\penalty", 1)) return "";
00929   if (is_tuple (t, "\\url", 1))
00930     return tree (APPLY, "href", t2e (t[1]));
00931   if (is_tuple (t, "\\href", 2))
00932     return tree (APPLY, "hlink", l2e (t[2]), t2e (t[1]));
00933 
00934   if (is_tuple (t, "\\xminus", 1))
00935     return tree (LONG_ARROW, "<rubber-minus>", l2e (t[1]));
00936   if (is_tuple (t, "\\xleftarrow", 1))
00937     return tree (LONG_ARROW, "<rubber-leftarrow>", l2e (t[1]));
00938   if (is_tuple (t, "\\xrightarrow", 1))
00939     return tree (LONG_ARROW, "<rubber-rightarrow>", l2e (t[1]));
00940   if (is_tuple (t, "\\xleftrightarrow", 1))
00941     return tree (LONG_ARROW, "<rubber-leftrightarrow>", l2e (t[1]));
00942   if (is_tuple (t, "\\xmapsto", 1))
00943     return tree (LONG_ARROW, "<rubber-mapsto>", l2e (t[1]));
00944   if (is_tuple (t, "\\xmapsfrom", 1))
00945     return tree (LONG_ARROW, "<rubber-mapsfrom>", l2e (t[1]));
00946   if (is_tuple (t, "\\xequal", 1))
00947     return tree (LONG_ARROW, "<rubber-equal>", l2e (t[1]));
00948   if (is_tuple (t, "\\xLeftarrow", 1))
00949     return tree (LONG_ARROW, "<rubber-Leftarrow>", l2e (t[1]));
00950   if (is_tuple (t, "\\xRightarrow", 1))
00951     return tree (LONG_ARROW, "<rubber-Rightarrow>", l2e (t[1]));
00952   if (is_tuple (t, "\\xLeftrightarrow", 1))
00953     return tree (LONG_ARROW, "<rubber-Leftrightarrow>", l2e (t[1]));
00954   if (is_tuple (t, "\\xminus*", 2))
00955     return tree (LONG_ARROW, "<rubber-minus>", l2e (t[1]), l2e (t[2]));
00956   if (is_tuple (t, "\\xleftarrow*", 2))
00957     return tree (LONG_ARROW, "<rubber-leftarrow>", l2e (t[1]), l2e (t[2]));
00958   if (is_tuple (t, "\\xrightarrow*", 2))
00959     return tree (LONG_ARROW, "<rubber-rightarrow>", l2e (t[1]), l2e (t[2]));
00960   if (is_tuple (t, "\\xleftrightarrow*", 2))
00961     return tree (LONG_ARROW, "<rubber-leftrightarrow>",
00962                  l2e (t[1]), l2e (t[2]));
00963   if (is_tuple (t, "\\xmapsto*", 2))
00964     return tree (LONG_ARROW, "<rubber-mapsto>", l2e (t[1]), l2e (t[2]));
00965   if (is_tuple (t, "\\xmapsfrom*", 2))
00966     return tree (LONG_ARROW, "<rubber-mapsfrom>", l2e (t[1]), l2e (t[2]));
00967   if (is_tuple (t, "\\xequal*", 2))
00968     return tree (LONG_ARROW, "<rubber-equal>", l2e (t[1]), l2e (t[2]));
00969   if (is_tuple (t, "\\xLeftarrow*", 2))
00970     return tree (LONG_ARROW, "<rubber-Leftarrow>", l2e (t[1]), l2e (t[2]));
00971   if (is_tuple (t, "\\xRightarrow*", 2))
00972     return tree (LONG_ARROW, "<rubber-Rightarrow>", l2e (t[1]), l2e (t[2]));
00973   if (is_tuple (t, "\\xLeftrightarrow*", 2))
00974     return tree (LONG_ARROW, "<rubber-Leftrightarrow>",
00975                  l2e (t[1]), l2e (t[2]));
00976 
00977   // Start TeXmacs specific markup
00978   if (is_tuple (t, "\\tmmathbf", 1))
00979     return tree (CONCAT,
00980                tree (SET, MATH_FONT_SERIES, "bold"),
00981                l2e (t[1]),
00982                tree (RESET, MATH_FONT_SERIES));
00983   if (is_tuple (t, "\\tmop", 1)) return t2e (t[1]);
00984   if (is_tuple (t, "\\tmstrong", 1)) return tree (APPLY, "strong", l2e (t[1]));
00985   if (is_tuple (t, "\\tmem", 1)) return tree (APPLY, "em", l2e (t[1]));
00986   if (is_tuple (t, "\\tmtt", 1)) return tree (APPLY, "tt", l2e (t[1]));
00987   if (is_tuple (t, "\\tmname", 1)) return tree (APPLY, "name", l2e (t[1]));
00988   if (is_tuple (t, "\\tmsamp", 1)) return tree (APPLY, "samp", l2e (t[1]));
00989   if (is_tuple (t, "\\tmabbr", 1)) return tree (APPLY, "abbr", l2e (t[1]));
00990   if (is_tuple (t, "\\tmdfn", 1)) return tree (APPLY, "dfn", l2e (t[1]));
00991   if (is_tuple (t, "\\tmkbd", 1)) return tree (APPLY, "kbd", l2e (t[1]));
00992   if (is_tuple (t, "\\tmvar", 1)) return tree (APPLY, "var", l2e (t[1]));
00993   if (is_tuple (t, "\\tmacronym", 1))
00994     return tree (APPLY, "acronym", l2e (t[1]));
00995   if (is_tuple (t, "\\tmperson", 1)) return tree (APPLY, "person", l2e (t[1]));
00996   if (is_tuple (t, "\\tmscript", 1)) return l2e (t[1]);
00997   if (is_tuple (t, "\\tmhlink", 1))
00998     return tree (HLINK, l2e (t[1]), l2e (t[2]));
00999   if (is_tuple (t, "\\tmaction", 1))
01000     return tree (ACTION, l2e (t[1]), l2e (t[2]));
01001   if (is_tuple (t, "\\foldtext", 2))
01002     return compound ("fold-text", l2e (t[1]), l2e (t[2]));
01003   if (is_tuple (t, "\\foldproof", 2))
01004     return compound ("fold-proof", l2e (t[1]), l2e (t[2]));
01005   if (is_tuple (t, "\\foldalgorithm", 2))
01006     return compound ("fold-algorithm", l2e (t[1]), l2e (t[2]));
01007   if (is_tuple (t, "\\foldexercise", 2))
01008     return compound ("fold-exercise", l2e (t[1]), l2e (t[2]));
01009   // End TeXmacs specific markup
01010 
01011   int i;
01012   string s= t[0]->label;
01013   tree r (APPLY, s(1,N(s)));
01014   if ((N(s)>7) && (s(0,7)=="\\begin-"))
01015     r= tree (BEGIN, s(7,N(s)));
01016   for (i=1; i<N(t); i++)
01017     r << l2e(t[i]);
01018   return r;
01019 }
01020 
01021 tree
01022 l2e (tree t) {
01023   if (is_atomic (t)) return latex_symbol_to_tree (t->label);
01024   if (L(t) == CONCAT) {
01025     bool new_flag= false;
01026     return latex_concat_to_tree (t, new_flag);
01027   }
01028   if (is_tuple (t) && (N(t)==1)) return latex_symbol_to_tree (t[0]->label);
01029   return latex_command_to_tree (t);
01030 }
01031 
01032 #undef var_m2e
01033 #undef m2e
01034 #undef t2e
01035 #undef l2e
01036 
01037 /******************************************************************************
01038 * Final modifications to the converted tree
01039 ******************************************************************************/
01040 
01041 static tree
01042 finalize_returns (tree t) {
01043   if (is_atomic (t)) return t;
01044   int  i, n= N(t);
01045   tree u (t, n);
01046   for (i=0; i<n; i++) u[i]= finalize_returns (t[i]);
01047   if (is_func (u, CONCAT)) {
01048     tree r (CONCAT);
01049     for (i=0; i<n; i++) {
01050       if (is_func (u[i], CONCAT)) r << A(u[i]);
01051       else if (is_compound (u[i])) r << u[i];
01052       else {
01053        int j= 0;
01054        string s= u[i]->label;
01055        while (j<N(s)) {
01056          int start= j;
01057            while ((j<N(s)) && (s[j]!='\n')) j++;
01058            if (j>start) r << s(start,j);
01059            if (j<N(s)) { r << tree (FORMAT, "new line"); j++; }
01060        }
01061       }
01062     }
01063     if (N(r)==0) return "";
01064     if (N(r)==1) return r[0];
01065     return r;
01066   }
01067   else return u;
01068 }
01069 
01070 static tree
01071 parse_matrix_params (tree t) {
01072   tree tformat (TFORMAT);
01073   if (N(t) <= 1) return tformat;
01074   string s= string_arg (t[1]);
01075   int i, n= N(s), col=1;
01076   for (i=0; i<n; i++) {
01077     switch (s[i]) {
01078     case 'l':
01079     case 'c':
01080     case 'r':
01081       {
01082        string col_s = as_string (col);
01083        string halign= copy (CELL_HALIGN);
01084        string how   = s (i, i+1);
01085        tformat << tree (CWITH, "1", "-1", col_s, col_s, halign, how);
01086        col++;
01087        break;
01088       }
01089     case '|':
01090       {
01091        string col_s= col==1? as_string (col): as_string (col-1);
01092        string hbor = col==1? copy (CELL_LBORDER): copy (CELL_RBORDER);
01093        string how  = "1ln";
01094        tformat << tree (CWITH, "1", "-1", col_s, col_s, hbor, how);
01095        break;
01096       }
01097     case '@':
01098       // FIXME: emergency exit; parameters of @ no longer between {}
01099       return tformat;
01100     }
01101   }
01102   return tformat;
01103 }
01104 
01105 static void
01106 parse_pmatrix (tree& r, tree t, int& i, string lb, string rb, string fm) {
01107   tree tformat= parse_matrix_params (t[i]);
01108   if (lb != "") r << tree (LEFT, lb);
01109 
01110   int rows=0, cols=0;
01111   tree V (CONCAT);
01112   tree L (CONCAT);
01113   tree E (CONCAT);
01114   for (i++; i<N(t); i++) {
01115     tree v= t[i];
01116     if (v == tree (FORMAT, "line separator")) {
01117       L << simplify_concat (E);
01118       E= tree (CONCAT);
01119       continue;
01120     }
01121     else if (v == tree (FORMAT, "next line")) {
01122       L << simplify_concat (E);
01123       V << L;
01124       cols= max (cols, N(L));
01125       L= tree (CONCAT);
01126       E= tree (CONCAT);
01127       continue;
01128     }
01129     else if (is_func (v, BEGIN) && (v[0] == "array" || v[0] == "tabular")) {
01130       parse_pmatrix (E, t, i, "", "", "tabular*");
01131       if (i<N(t)) continue;
01132       break;
01133     }
01134     else if (v == tree (BEGIN, "stack")) {
01135       parse_pmatrix (E, t, i, "", "", "stack");
01136       if (i<N(t)) continue;
01137       break;
01138     }
01139     else if (v == tree (BEGIN, "cases")) {
01140       parse_pmatrix (E, t, i, "", "", "choice");
01141       if (i<N(t)) continue;
01142       break;
01143     }
01144     else if (v == tree (BEGIN, "matrix")) {
01145       parse_pmatrix (E, t, i, "", "", "tabular*");
01146       if (i<N(t)) continue;
01147       break;
01148     }
01149     else if (v == tree (BEGIN, "pmatrix")) {
01150       parse_pmatrix (E, t, i, "", "", "matrix");
01151       if (i<N(t)) continue;
01152       break;
01153     }
01154     else if (v == tree (BEGIN, "bmatrix")) {
01155       parse_pmatrix (E, t, i, "[", "]", "tabular*");
01156       if (i<N(t)) continue;
01157       break;
01158     }
01159     else if (v == tree (BEGIN, "vmatrix")) {
01160       parse_pmatrix (E, t, i, "", "", "det");
01161       if (i<N(t)) continue;
01162       break;
01163     }
01164     else if (v == tree (BEGIN, "smallmatrix")) {
01165       parse_pmatrix (E, t, i, "", "", "matrix*");
01166       if (i<N(t)) continue;
01167       break;
01168     }
01169     else if (v == tree (END, "array")) break;
01170     else if (v == tree (END, "tabular")) break;
01171     else if (v == tree (END, "cases")) break;
01172     else if (v == tree (END, "stack")) break;
01173     else if (v == tree (END, "matrix")) break;
01174     else if (v == tree (END, "pmatrix")) break;
01175     else if (v == tree (END, "bmatrix")) break;
01176     else if (v == tree (END, "vmatrix")) break;
01177     else if (v == tree (END, "smallmatrix")) break;
01178     else if (v == tree (APPLY, "hline")) {
01179       int    row  = N(V)+ (N(L)==0? 0: 1);
01180       string row_s= row==0? as_string (row+1): as_string (row);
01181       string vbor = row==0? copy (CELL_TBORDER): copy (CELL_BBORDER);
01182       string how  = "1ln";
01183       tformat << tree (CWITH, row_s, row_s, "1", "-1", vbor, how);
01184     }
01185     else E << v;
01186   }
01187   if ((N(L)>0) || (N(E)>0)) {
01188     L << simplify_concat (E);
01189     V << L;
01190   }
01191   if ((max (cols, N(L)) * N(V)) == 0) {
01192     L= tree (CONCAT, "");
01193     V= tree (CONCAT, tree (CONCAT, ""));
01194   }
01195   cols= max (cols, N(L));
01196   rows= N(V);
01197 
01198   int x, y;
01199   tree M (TABLE);
01200   for (y=0; y<rows; y++) {
01201     tree R (ROW);
01202     for (x=0; x<cols; x++)
01203       if (x<N(V[y])) R << tree (CELL, V[y][x]);
01204       else R << tree (CELL, "");
01205     M << R;
01206   }
01207   r << compound (fm, tree (TFORMAT, M));
01208   if (rb != "") r << tree (RIGHT, rb);
01209 }
01210 
01211 static tree
01212 finalize_pmatrix (tree t) {
01213   if (is_atomic (t)) return t;
01214   int  i, n= N(t);
01215   tree u (t, n);
01216   for (i=0; i<n; i++) u[i]= finalize_pmatrix (t[i]);
01217   if (is_func (u, CONCAT)) {
01218     tree r (CONCAT);
01219     for (i=0; i<n; i++)
01220       if (is_func (u[i], BEGIN)) {
01221        if (u[i][0] == "array")
01222          parse_pmatrix (r, u, i, "", "", "tabular*");
01223        else if (u[i][0] == "tabular")
01224          parse_pmatrix (r, u, i, "", "", "tabular*");
01225        else if (u[i][0] == "cases")
01226          parse_pmatrix (r, u, i, "", "", "choice");
01227        else if (u[i][0] == "stack")
01228          parse_pmatrix (r, u, i, "", "", "stack");
01229        else if (u[i][0] == "matrix")
01230          parse_pmatrix (r, u, i, "", "", "tabular*");
01231        else if (u[i][0] == "pmatrix")
01232          parse_pmatrix (r, u, i, "", "", "matrix");
01233        else if (u[i][0] == "bmatrix")
01234          parse_pmatrix (r, u, i, "[", "]", "tabular*");
01235        else if (u[i][0] == "vmatrix")
01236          parse_pmatrix (r, u, i, "", "", "det");
01237        else if (u[i][0] == "smallmatrix")
01238          parse_pmatrix (r, u, i, "", "", "matrix*");
01239        else r << u[i];
01240       }
01241       else r << u[i];
01242     return r;
01243   }
01244   else if (is_func (u, APPLY, 2) && (u[0] == "matrix"))
01245     return tree (APPLY, "tabular*", u[1]);
01246   else if (is_func (u, APPLY, 2) && (u[0] == "smallmatrix"))
01247     return tree (APPLY, "matrix*", u[1]);
01248   else if (is_func (u, APPLY, 2) && (u[0] == "substack")) {
01249     tree cc (CONCAT);
01250     cc << tree (BEGIN, "stack");
01251     if (is_func (u[1], CONCAT)) cc << A(u[1]);
01252     else cc << u[1];
01253     cc << tree (END, "stack");
01254     return finalize_pmatrix (cc);
01255   }
01256   else return u;
01257 }
01258 
01259 static void
01260 remove_space (tree& t) {
01261   if (arity (t) == 0) return;
01262   if (is_compound (t[N(t)-1])) return;
01263   string s= t[N(t)-1]->label;
01264   if ((N(s)>0) && (s[N(s)-1]==' '))
01265     t[N(t)-1]= s(0,N(s)-1);
01266 }
01267 
01268 static void
01269 insert_return (tree& t) {
01270   remove_space (t);
01271   if ((arity(t)>0) && (t[N(t)-1]==tree (FORMAT, "new line"))) return;
01272   t << tree (FORMAT, "new line");
01273 }
01274 
01275 static bool
01276 space_eater (tree t) {
01277   return is_func (t, FORMAT, 1) && (t[0]->label != "new line");
01278 }
01279 
01280 static bool
01281 admissible_env (tree t) {
01282   string s= t[0]->label;
01283   if (ends (s, "*")) s= s (0, N(s)-1);
01284   if (latex_type ("\\begin-" * s) == "list") return true;
01285   if (latex_type ("\\begin-" * s) == "environment") return true;
01286   if (latex_type ("\\begin-" * s) == "math-environment") return true;
01287   return false;
01288 }
01289 
01290 static string
01291 translate_list (string s) {
01292   if (s == "itemizeminus") return "itemize-minus";
01293   if (s == "itemizedot") return "itemize-dot";
01294   if (s == "itemizearrow") return "itemize-arrow";
01295   if (s == "enumeratenumeric") return "enumerate-numeric";
01296   if (s == "enumerateroman") return "enumerate-roman";
01297   if (s == "enumerateromancap") return "enumerate-romancap";
01298   if (s == "enumeratealpha") return "enumerate-alpha";
01299   if (s == "enumeratealphacap") return "enumerate-alphacap";
01300   if (s == "asparaitem") return "itemize";
01301   if (s == "inparaitem") return "itemize";
01302   if (s == "compactitem") return "itemize";
01303   if (s == "asparaenum") return "enumerate";
01304   if (s == "inparaenum") return "enumerate";
01305   if (s == "compactenum") return "enumerate";
01306   if (s == "itemize*") return "itemize";
01307   if (s == "enumerate*") return "enumerate";
01308   if (s == "asparaitem*") return "itemize";
01309   if (s == "inparaitem*") return "itemize";
01310   if (s == "compactitem*") return "itemize";
01311   if (s == "asparaenum*") return "enumerate";
01312   if (s == "inparaenum*") return "enumerate";
01313   if (s == "compactenum*") return "enumerate";
01314   return s;
01315 }
01316 
01317 static tree
01318 finalize_layout (tree t) {
01319   if (is_atomic (t)) return t;
01320   int  i, n= N(t);
01321   tree u (t, n);
01322   for (i=0; i<n; i++) u[i]= finalize_layout (t[i]);
01323   if (is_func (u, CONCAT)) {
01324     bool spc_flag =false;
01325     bool item_flag=false;
01326     tree r (CONCAT);
01327     for (i=0; i<n; i++) {
01328       tree v= u[i];
01329 
01330       if (space_eater (v)) {
01331        remove_space (r);
01332        r << v;
01333        spc_flag = true;
01334        item_flag= false;
01335        continue;
01336       }
01337 
01338       if (is_func (v, BEGIN, 1) && (v[0] == "picture")) {
01339        for (; i<n; i++)
01340          if (is_func (u[i], IMAGE)) r << u[i];
01341          else if (is_func (u[i], END, 1) && (u[i][0] == "picture"))
01342            break;
01343        continue;
01344       }
01345 
01346       if (is_func (v, BEGIN) && ((v[0] == "figure") || (v[0] == "figure*"))) {
01347        r << tree (BEGIN, "bigfigure");
01348        continue;
01349       }
01350 
01351       if (is_func (v, END, 1) && (v[0] == "figure")) {
01352        r << tree (END, "bigfigure");
01353        continue;
01354       }
01355 
01356       if (is_func (v, BEGIN) && ((v[0] == "table") || (v[0] == "table*"))) {
01357        r << tree (BEGIN, "bigtable");
01358        continue;
01359       }
01360 
01361       if (is_func (v, END, 1) && (v[0] == "table")) {
01362        r << tree (END, "bigtable");
01363        continue;
01364       }
01365 
01366       /*
01367       if (is_func (v, BEGIN) && (v[0] == "hide-preamble")) {
01368        r << tree (BEGIN, "hide-preamble");
01369        continue;
01370       }
01371 
01372       if (is_func (v, END) && (v[0] == "hide-preamble")) {
01373        r << tree (END, "hide-preamble");
01374        continue;
01375       }
01376       */
01377 
01378       if ((is_func (v, BEGIN, 1) || is_func (v, BEGIN, 2))
01379           && admissible_env (v) && v[0] != "thebibliography") {
01380        if (v == tree (BEGIN, "verbatim")) {
01381          r << v; i++;
01382          if ((i<n) && (t[i] == tree (FORMAT, "new line"))) {
01383            remove_space (r);
01384            r << t[i]; i++;
01385          }
01386          while ((i<n) && (t[i] != tree (END, "verbatim"))) {
01387            if ((t[i] == tree (FORMAT, "new line")) &&
01388               (((i+1) == n) || (t[i+1] != tree (END, "verbatim"))))
01389              r << tree (FORMAT, "new line");
01390            else r << t[i];
01391            i++;
01392          }
01393          if (i<n) r << t[i];
01394          spc_flag = (t[i-1] == tree (FORMAT, "new line"));
01395          item_flag= false;
01396          continue;
01397        }
01398        
01399        if (v == tree (BEGIN, "displaymath"))
01400          v= tree (BEGIN, "equation*");
01401        if (v == tree (BEGIN, "math")) {
01402          r << tree (SET, MODE, "math");
01403          spc_flag = item_flag= false;
01404          continue;
01405        }
01406        
01407        insert_return (r);
01408        r << tree (BEGIN, translate_list (v[0]->label));
01409        spc_flag = true;
01410        item_flag= (latex_type ("\\begin-" * v[0]->label) == "list");
01411        continue;
01412       }
01413 
01414       if (is_func (v, END, 1) && admissible_env (v)) {
01415        if (v == tree (END, "displaymath"))
01416          v= tree (END, "equation*");
01417        if (v == tree (END, "math")) {
01418          r << tree (RESET, MODE);
01419          spc_flag = item_flag= false;
01420          continue;
01421        }
01422        
01423        remove_space (r);
01424        r << tree (END, translate_list (v[0]->label));
01425        if (((i+1) == N(t)) || (t[i+1] != tree (FORMAT, "new line")))
01426          insert_return (r);
01427        spc_flag = true;
01428        item_flag= false;
01429        continue;
01430       }
01431       
01432       if ((v == tree (APPLY, "item")) ||
01433          (is_func (v, APPLY, 2) && (v[0]->label == "item*"))) {
01434        if (!item_flag) insert_return (r);
01435        r << v;
01436        spc_flag = true;
01437        item_flag= false;
01438        continue;
01439       }
01440 
01441       if ((is_atomic (v)) && spc_flag &&
01442          (N(v->label)>0) && (v->label[0]==' '))
01443        {
01444          if (N(v->label)==1) continue;
01445          r << v->label (1, N(v->label));
01446        }
01447       else r << v;
01448       spc_flag = false;
01449       item_flag= false;
01450     }
01451     return r;
01452   }
01453   else return u;
01454 }
01455 
01456 static tree
01457 finalize_sections (tree t) {
01458   tree r (DOCUMENT);
01459   for (int i=0; i<N(t); i++) {
01460     tree u= t[i];
01461     if (is_concat (u) && N(u) >= 2 &&
01462        (is_var_compound (u[0], "part", 1) ||
01463         is_var_compound (u[0], "part*", 1) ||
01464         is_var_compound (u[0], "chapter", 1) ||
01465         is_var_compound (u[0], "chapter*", 1) ||
01466         is_var_compound (u[0], "section", 1) ||
01467         is_var_compound (u[0], "section*", 1) ||
01468         is_var_compound (u[0], "subsection", 1) ||
01469         is_var_compound (u[0], "subsection*", 1) ||
01470         is_var_compound (u[0], "subsubsection", 1) ||
01471         is_var_compound (u[0], "subsubsection*", 1)))
01472       {
01473        if (N(u) > 2 && u[1] == " ")
01474          u= u (0, 1) * u (2, N(u));
01475        if (!is_func (u[1], LABEL) || (N(u) >= 3 && !is_func (u[2], LABEL))) {
01476          if (!is_func (u[1], LABEL)) {
01477            r << u[0];
01478            if (N(u) == 2) u= u[1];
01479            else u= u (1, N(u));
01480          }
01481          else {
01482            r << u (0, 2);
01483            if (N(u) == 3) u= u[2];
01484            else u= u (2, N(u));
01485          }
01486          if (is_atomic (u) && starts (u->label, " "))
01487            u= u->label (1, N(u->label));
01488          if (is_concat (u) && is_atomic (u[0]) && starts (u[0]->label, " "))
01489            u= tree (CONCAT, u[0]->label (1, N(u[0]->label))) * u (1, N(u));
01490          r << u;
01491        }
01492        else r << u;
01493       }
01494     else r << u;
01495   }
01496   return r;
01497 }
01498 
01499 static tree
01500 finalize_document (tree t) {
01501   if (is_atomic (t)) t= tree (CONCAT, t);
01502   t= finalize_returns (t);
01503   t= finalize_pmatrix (t);
01504   t= finalize_layout (t);
01505   if (!is_func (t, CONCAT)) return tree (DOCUMENT, t);
01506 
01507   int i;
01508   tree r (DOCUMENT);
01509   for (i=0; i<N(t); i++) {
01510     int start= i;
01511     while ((i<N(t)) && (t[i]!=tree (FORMAT, "new line"))) i++;
01512     if (i==start) r << "";
01513     else if (i==(start+1)) r << t[start];
01514     else r << t(start,i);
01515     if (i==(N(t)-1)) r << "";
01516   }
01517   return finalize_sections (r);
01518 }
01519 
01520 bool
01521 is_preamble_command (tree t, tree& doc, string& style) {
01522   (void) doc;
01523   if (is_func (t, APPLY, 2)) {
01524     if (t[0] == "usepackage") return true;
01525     if ((t[0] == "documentstyle") ||
01526        (t[0] == "documentclass")) {
01527       style= string_arg (t[1]);
01528       return true;
01529     }
01530   }
01531   if (is_func (t, APPLY, 3)) {
01532     if (t[0] == "usepackage*") return true;
01533     if ((t[0] == "documentstyle*") ||
01534        (t[0] == "documentclass*")) {
01535       style= string_arg (t[2]);
01536       return true;
01537     }
01538   }
01539   if (is_func (t, BEGIN, 1) && (t[0] == "document")) return true;
01540   if (is_func (t, END, 1) && (t[0] == "document")) return true;
01541   return false;
01542 }
01543 
01544 bool
01545 is_bibliography_command (tree t, tree& doc, string& bib_style) {
01546   if (is_func (t, APPLY, 2)) {
01547     if (t[0] == "bibliographystyle") {
01548       bib_style= t[1]->label;
01549       return true;
01550     }
01551     if (t[0] == "bibliography") {
01552       tree begin (BEGIN, "bibliography");
01553       tree end (END, "bibliography");
01554       begin << "bib" << bib_style << t[1]->label;
01555       doc << begin << end;
01556       return true;
01557     }
01558   }
01559   return false;
01560 }
01561 
01562 tree
01563 finalize_preamble (tree t, string& style) {
01564   int i, j;
01565   tree u (DOCUMENT);
01566   style= "generic";
01567   string bib_style= "plain";
01568   for (i=0; i<N(t); i++) {
01569     if (is_concat (t[i])) {
01570       tree v (CONCAT);
01571       for (j=0; j<N(t[i]); j++)
01572        if (is_preamble_command (t[i][j], v, style));
01573        else if (is_bibliography_command (t[i][j], v, bib_style));
01574        else v << t[i][j];
01575       if (N(v)==1) u << v[0];
01576       if (N(v)>=2) u << v;
01577     }
01578     else if (is_preamble_command (t[i], u, style));
01579     else if (is_bibliography_command (t[i], u, bib_style));
01580     else u << t[i];
01581   }
01582   return u;
01583 }
01584 
01585 /******************************************************************************
01586 * Improper matches
01587 ******************************************************************************/
01588 
01589 void
01590 handle_improper_matches (tree& r, tree t, int& pos) {
01591   while (pos < N(t)) {
01592     if (is_func (t[pos], SET)) {
01593       tree b= t[pos++]; r << b;
01594       handle_improper_matches (r, t, pos);
01595       if ((pos < N(t)) && (t[pos][0] == b[0])) r << t[pos++];
01596       else {
01597        r << tree (RESET, copy (b[0]));
01598        return;
01599       }
01600     }
01601     else if (is_func (t[pos], RESET)) return;
01602     else r << t[pos++];
01603   }
01604 }
01605 
01606 tree
01607 remove_env_spaces (tree t, bool& done) {
01608   if (is_atomic (t)) {
01609     done= done || (t != "" && t != " ");
01610     return t;
01611   }
01612   else if (is_func (t, CONCAT)) {
01613     array<tree> r;
01614     for (int i=0; i<N(t); i++)
01615       if (!done && t[i] == "");
01616       else if (!done && t[i] == " ");
01617       else r << remove_env_spaces (t[i], done);
01618     return simplify_concat (tree (CONCAT, r));
01619   }
01620   else if (is_func (t, WITH)) {
01621     tree r= t (0, N(t));
01622     r[N(t)-1]= remove_env_spaces (r[N(t)-1], done);
01623     return r;
01624   }
01625   else return t;
01626 }
01627 
01628 tree
01629 env_hacks (tree t) {
01630   int i, n= N(t);
01631   bool done= false;
01632   tree beg= remove_env_spaces (t[n-2], done);
01633   tree end= remove_env_spaces (t[n-1], done);
01634   if (beg == "") beg= tree (CONCAT);
01635   else if (!is_concat (beg)) beg= tree (CONCAT, beg);
01636   if (end == "") end= tree (CONCAT);
01637   else if (!is_concat (end)) end= tree (CONCAT, end);
01638   array<tree> ba;
01639   array<tree> ea;
01640   for (i=0; i<N(beg); i++)
01641     if (is_func (beg[i], VSPACE))
01642       ba << tree (VAR_VSPACE, A(beg[i]));
01643     else if (is_func (beg[i], PAGE_BREAK))
01644       ba << tree (VAR_PAGE_BREAK, A(beg[i]));
01645     else if (is_func (beg[i], NO_PAGE_BREAK))
01646       ba << tree (VAR_NO_PAGE_BREAK, A(beg[i]));
01647     else if (is_func (beg[i], NEW_PAGE))
01648       ba << tree (VAR_NEW_PAGE, A(beg[i]));
01649     else ba << beg[i];
01650   for (i=0; i<N(end); i++)
01651     if (is_func (end[i], NO_INDENT))
01652       ea << tree (VAR_NO_INDENT, A(end[i]));
01653     else if (is_func (end[i], YES_INDENT))
01654       ea << tree (VAR_YES_INDENT, A(end[i]));
01655     else ea << end[i];
01656   beg= tree (CONCAT, ba);
01657   end= tree (CONCAT, ea);
01658   for (i=N(beg); i>0 && is_func (beg[i-1], RESET, 1); i--) ;
01659   bool ok= (i<<1) >= N(beg);
01660   for (int k=0; k<N(beg)-i; k++) {
01661     ok= ok && is_func (beg[i-k-1], SET, 2) && beg[i-k-1][0] == beg[i+k][0];
01662     //cout << "Matched " << beg[i-k-1] << " and " << beg[i+k] << "\n";
01663   }
01664   if (ok && i<N(beg)) {
01665     tree r= t (0, n);
01666     r[n-2]= simplify_concat (beg (0, i));
01667     r[n-1]= simplify_concat (beg (i, N(beg)) * end);
01668     //cout << "<< " << t << "\n";
01669     //cout << ">> " << r << "\n";
01670     t= r;
01671   }
01672   return t;
01673 }
01674 
01675 tree
01676 handle_improper_matches (tree t) {
01677   if (is_atomic (t)) return t;
01678   else {
01679     int i, n= N(t);
01680     tree r (t, n);
01681     for (i=0; i<n; i++)
01682       r[i]= handle_improper_matches (t[i]);
01683     if (is_concat (r)) {
01684       int pos;
01685       tree u (r, 0);
01686       for (pos=0; pos<N(r); pos++)
01687        handle_improper_matches (u, r, pos);
01688       if (N(u)==0) return "";
01689       if (N(u)==1) return u[0];
01690       return u;
01691     }
01692     else if (is_func (r, ENV) && N(r) >= 2)
01693       return env_hacks (r);
01694     return r;
01695   }
01696 }
01697 
01698 /******************************************************************************
01699 * Further finalization after upgrading
01700 ******************************************************************************/
01701 
01702 tree
01703 float_body (tree t) {
01704   if (is_atomic (t)) return t;
01705   else if (is_var_compound (t, "caption", 1)) return "";
01706   else if (is_var_compound (t, "center", 1)) return float_body (t[N(t)-1]);
01707   else {
01708     int i, n= N(t);
01709     tree r (t, n);
01710     for (i=0; i<n; i++)
01711       r[i]= float_body (t[i]);
01712     if (is_document (r) && (n>0) && (r[n-1] == "")) r= r (0, n-1);
01713     return r;
01714   }
01715 }
01716 
01717 tree
01718 find_caption (tree t) {
01719   if (is_atomic (t)) return "";
01720   else if (is_var_compound (t, "caption", 1)) return t[N(t)-1];
01721   else {
01722     int i, n= N(t);
01723     for (i=0; i<n; i++) {
01724       tree r= find_caption (t[i]);
01725       if (r != "") return r;
01726     }
01727     return "";
01728   }
01729 }
01730 
01731 tree
01732 finalize_floats (tree t) {
01733   if (is_atomic (t)) return t;
01734   else if (is_var_compound (t, "bigfigure", 1)) {
01735     tree body= float_body (t[N(t)-1]);
01736     tree capt= find_caption (t[N(t)-1]);
01737     return tree (make_tree_label ("big-figure"), body, capt);
01738   }
01739   else if (is_var_compound (t, "bigtable", 1)) {
01740     tree body= float_body (t[N(t)-1]);
01741     tree capt= find_caption (t[N(t)-1]);
01742     return tree (make_tree_label ("big-table"), body, capt);
01743   }
01744   else {
01745     int i, n= N(t);
01746     tree r (t, n);
01747     for (i=0; i<n; i++)
01748       r[i]= finalize_floats (t[i]);
01749     return r;
01750   }
01751 }
01752 
01753 static bool
01754 is_hyper_link (string s) {
01755   return starts (s, "http://") || starts (s, "ftp://");
01756 }
01757 
01758 tree
01759 finalize_misc (tree t) {
01760   if (is_atomic (t)) return t;
01761   else if (is_compound (t, "verbatim", 1) &&
01762            is_atomic (t[0]) && is_hyper_link (t[0]->label)) {
01763     return compound ("href", finalize_misc (t[0]));
01764   }
01765   else if (is_func (t, WITH, 3) && t[0] == FONT_FAMILY && t[1] == "tt" &&
01766            is_atomic (t[2]) && is_hyper_link (t[2]->label)) {
01767     return compound ("href", finalize_misc (t[2]));
01768   }
01769   else if (is_compound (t, "flushleft", 1) ||
01770            is_compound (t, "leftaligned", 1))
01771     return compound ("left-aligned", finalize_misc (t[0]));
01772   else if (is_compound (t, "flushright", 1) ||
01773            is_compound (t, "rightaligned", 1))
01774     return compound ("right-aligned", finalize_misc (t[0]));
01775   else if (is_compound (t, "acknowledgments", 1))
01776     return compound ("acknowledgments*", finalize_misc (t[0]));
01777   else if (is_compound (t, "text", 1) &&
01778            is_func (t[0], WITH, 3) &&
01779            t[0][0] == "font-family" &&
01780            t[0][1] == "rm")
01781     return compound ("math-up", finalize_misc (t[0][2]));
01782   else {
01783     int i, n= N(t);
01784     tree r (t, n);
01785     for (i=0; i<n; i++)
01786       r[i]= finalize_misc (t[i]);
01787     return r;
01788   }
01789 }
01790 
01791 /******************************************************************************
01792 * Final changes programmed in Guile
01793 ******************************************************************************/
01794 
01795 tree
01796 finalize_textm (tree t) {
01797   tree u= stree_to_tree (call ("textm-finalize", tree_to_stree (t)));
01798   return simplify_correct (u);
01799 }
01800 
01801 /******************************************************************************
01802 * Interface
01803 ******************************************************************************/
01804 
01805 tree
01806 latex_to_tree (tree t1) {
01807   string style, lan= "";
01808   bool is_document= is_compound (t1, "!file", 1);
01809   if (is_document) t1= t1[0];
01810   if (is_compound (t1, "!language", 2)) {
01811     lan= t1[1]->label;
01812     t1 = t1[0];
01813   }
01814   textm_appendices= false;
01815   textm_unicode   = false;
01816   textm_natbib    = false;
01817   command_type ("!em") = "false";
01818   //cout << "\n\nt1= " << t1 << "\n\n";
01819   tree t2= is_document? filter_preamble (t1): t1;
01820   //cout << "\n\nt2= " << t2 << "\n\n";
01821   tree t3= parsed_latex_to_tree (t2);
01822   //cout << "\n\nt3= " << t3 << "\n\n";
01823   tree t4= finalize_document (t3);
01824   // cout << "\n\nt4= " << t4 << "\n\n";
01825   tree t5= is_document? finalize_preamble (t4, style): t4;
01826   // cout << "\n\nt5= " << t5 << "\n\n";
01827   tree t6= handle_improper_matches (t5);
01828   //cout << "\n\nt6= " << t6 << "\n\n";
01829   if ((!is_document) && is_func (t6, DOCUMENT, 1)) t6= t6[0];
01830   tree t7= upgrade_tex (t6);
01831   //cout << "\n\nt7= " << t7 << "\n\n";
01832   tree t8= finalize_floats (t7);
01833   // cout << "\n\nt8= " << t8 << "\n\n";
01834   tree t9= finalize_misc (t8);
01835   // cout << "\n\nt9= " << t9 << "\n\n";
01836   tree t10= finalize_textm (t9);
01837   // cout << "\n\nt10= " << t10 << "\n\n";
01838   tree t11= drd_correct (std_drd, t10);
01839   // cout << "\n\nt11= " << t11 << "\n\n";
01840 
01841   if (!exists (url ("$TEXMACS_STYLE_PATH", style * ".ts")))
01842     style= "generic";
01843   tree initial (COLLECTION), mods (WITH);
01844   if (textm_unicode) {
01845     string name= "modern";
01846     if (lan == "chinese") name= "fireflysung";
01847     //if (lan == "japanese") name= "ipa";
01848     //if (lan == "korean") name= "unbatang";
01849     if (lan == "taiwanese") name= "fireflysung";
01850     initial << tree (ASSOCIATE, FONT, name);
01851     mods << tree (FONT) << tree (name);
01852   }
01853   if (lan != "") {
01854     initial << tree (ASSOCIATE, LANGUAGE, lan);
01855     mods << tree (LANGUAGE) << tree (lan);
01856   }
01857 
01858   tree t12= t11;
01859   if (is_document) t12= simplify_correct (t11);
01860   else if (N (mods) > 0) { t12= mods; t12 << t11; }
01861   // cout << "\n\nt12= " << t12 << "\n\n";
01862   tree t13= latex_correct (t12);
01863   // cout << "\n\nt13= " << t13 << "\n\n";
01864 
01865   if (is_document) {
01866     tree the_body   = compound ("body", t13);
01867     tree the_style  = compound ("style", style);
01868     tree the_initial= compound ("initial", initial);
01869     if (textm_natbib)
01870       the_style= compound ("style", tuple (style, "cite-author-year"));
01871     if (N (initial) == 0) return tree (DOCUMENT, the_style, the_body);
01872     else return tree (DOCUMENT, the_style, the_body, the_initial);
01873   }
01874   else return t13;
01875 }
01876 
01877 tree
01878 latex_document_to_tree (string s) {
01879   command_type ->extend ();
01880   command_arity->extend ();
01881   command_def  ->extend ();
01882   tree t= parse_latex_document (s, true);
01883   tree r= latex_to_tree (t);
01884   command_type ->shorten ();
01885   command_arity->shorten ();
01886   command_def  ->shorten ();
01887   return r;
01888 }