diff options
author | Pierre Schmitz <pierre@archlinux.de> | 2006-10-11 18:12:39 +0000 |
---|---|---|
committer | Pierre Schmitz <pierre@archlinux.de> | 2006-10-11 18:12:39 +0000 |
commit | 183851b06bd6c52f3cae5375f433da720d410447 (patch) | |
tree | a477257decbf3360127f6739c2f9d0ec57a03d39 /math |
MediaWiki 1.7.1 wiederhergestellt
Diffstat (limited to 'math')
-rw-r--r-- | math/.htaccess | 1 | ||||
-rw-r--r-- | math/.svnignore | 7 | ||||
-rw-r--r-- | math/Makefile | 64 | ||||
-rw-r--r-- | math/README | 107 | ||||
-rw-r--r-- | math/TODO | 3 | ||||
-rw-r--r-- | math/html.ml | 119 | ||||
-rw-r--r-- | math/html.mli | 5 | ||||
-rw-r--r-- | math/lexer.mll | 93 | ||||
-rw-r--r-- | math/mathml.ml | 20 | ||||
-rw-r--r-- | math/mathml.mli | 1 | ||||
-rw-r--r-- | math/parser.mly | 103 | ||||
-rw-r--r-- | math/render.ml | 33 | ||||
-rw-r--r-- | math/render_info.mli | 20 | ||||
-rw-r--r-- | math/tex.mli | 19 | ||||
-rw-r--r-- | math/texutil.ml | 482 | ||||
-rw-r--r-- | math/texutil.mli | 11 | ||||
-rw-r--r-- | math/texvc.ml | 34 | ||||
-rw-r--r-- | math/texvc_cgi.ml | 62 | ||||
-rw-r--r-- | math/texvc_test.ml | 25 | ||||
-rw-r--r-- | math/texvc_tex.ml | 3 | ||||
-rw-r--r-- | math/util.ml | 17 |
21 files changed, 1229 insertions, 0 deletions
diff --git a/math/.htaccess b/math/.htaccess new file mode 100644 index 00000000..3a428827 --- /dev/null +++ b/math/.htaccess @@ -0,0 +1 @@ +Deny from all diff --git a/math/.svnignore b/math/.svnignore new file mode 100644 index 00000000..6aa96403 --- /dev/null +++ b/math/.svnignore @@ -0,0 +1,7 @@ +texvc +texvc_test +texvc_tex +*.cmi +*.cmx +*.mli +*~ diff --git a/math/Makefile b/math/Makefile new file mode 100644 index 00000000..47c40f96 --- /dev/null +++ b/math/Makefile @@ -0,0 +1,64 @@ +OBJ=render_info.cmo tex.cmo texutil.cmo parser.cmo lexer.cmo texvc.cmo \ +render_info.cmx tex.cmx texutil.cmx parser.cmx lexer.cmx texvc.cmx \ +lexer.cmi parser.cmi render_info.cmi tex.cmi texutil.cmi texvc.cmi \ +lexer.o parser.o render_info.o tex.o texutil.o texvc.o \ +lexer.ml parser.ml parser.mli texvc texvc.bc texvc_test.cmo \ +texvc_test.cmx texvc_test.cmi texvc_test.o texvc_test util.o \ +util.cmo util.cmx util.cmi texvc_cgi.cmi texvc_cgi texvc_cgi.cmo \ +render.o render.cmi render.cmo render.cmx texvc_tex.cmx \ +texvc_tex.o texvc_tex.cmi texvc_tex html.cmi html.cmo html.cmx \ +html.o mathml.cmi mathml.cmo mathml.cmx mathml.o +CGIPATH=-I /usr/lib/ocaml/cgi -I /usr/lib/ocaml/netstring -I /usr/lib/ocaml/pcre + +all: texvc texvc_test texvc_tex +texvc.bc: util.cmo parser.cmo html.cmo mathml.cmo texutil.cmo render.cmo lexer.cmo texvc.cmo + ocamlc -o $@ unix.cma $^ +texvc: util.cmx parser.cmx html.cmx mathml.cmx texutil.cmx render.cmx lexer.cmx texvc.cmx + ocamlopt -o $@ unix.cmxa $^ +texvc_test: util.cmx parser.cmx html.cmx mathml.cmx texutil.cmx lexer.cmx texvc_test.cmx + ocamlopt -o $@ $^ +texvc_tex: util.cmx parser.cmx html.cmx mathml.cmx texutil.cmx lexer.cmx texvc_tex.cmx + ocamlopt -o $@ $^ +%.ml: %.mll + ocamllex $< +%.mli %.ml: %.mly + ocamlyacc $< +%.cmo: %.ml + ocamlc -c $< +%.cmx: %.ml + ocamlopt -c $< +%.cmi: %.mli + ocamlc -c $< +texvc_cgi.cmo: texvc_cgi.ml + ocamlc -c $(CGIPATH) $< +texvc_cgi: util.cmo parser.cmo texutil.cmo render.cmo lexer.cmo texvc_cgi.cmo + ocamlc -o $@ unix.cma $(CGIPATH) pcre.cma netstring.cma cgi.cma $^ + chmod g-w $@ +clean: + rm -f $(OBJ) + +html.cmo: render_info.cmi tex.cmi util.cmo html.cmi +html.cmx: render_info.cmi tex.cmi util.cmx html.cmi +html.cmi: tex.cmi +lexer.cmo: parser.cmi render_info.cmi tex.cmi texutil.cmi +lexer.cmx: parser.cmx render_info.cmi tex.cmi texutil.cmx +mathml.cmo: tex.cmi mathml.cmi +mathml.cmx: tex.cmi mathml.cmi +mathml.cmi: tex.cmi +parser.cmo: render_info.cmi tex.cmi parser.cmi +parser.cmx: render_info.cmi tex.cmi parser.cmi +parser.cmi: render_info.cmi tex.cmi +render.cmo: texutil.cmi util.cmo +render.cmx: texutil.cmx util.cmx +tex.cmi: render_info.cmi +texutil.cmo: html.cmi parser.cmi render_info.cmi tex.cmi util.cmo texutil.cmi +texutil.cmx: html.cmx parser.cmx render_info.cmi tex.cmi util.cmx texutil.cmi +texutil.cmi: parser.cmi tex.cmi +texvc.cmo: html.cmi lexer.cmo mathml.cmi parser.cmi render.cmo texutil.cmi util.cmo +texvc.cmx: html.cmx lexer.cmx mathml.cmx parser.cmx render.cmx texutil.cmx util.cmx +texvc_cgi.cmo: lexer.cmo parser.cmi render.cmo texutil.cmi util.cmo +texvc_cgi.cmx: lexer.cmx parser.cmx render.cmx texutil.cmx util.cmx +texvc_test.cmo: html.cmi lexer.cmo parser.cmi texutil.cmi util.cmo +texvc_test.cmx: html.cmx lexer.cmx parser.cmx texutil.cmx util.cmx +texvc_tex.cmo: lexer.cmo parser.cmi texutil.cmi util.cmo +texvc_tex.cmx: lexer.cmx parser.cmx texutil.cmx util.cmx diff --git a/math/README b/math/README new file mode 100644 index 00000000..e58cbf04 --- /dev/null +++ b/math/README @@ -0,0 +1,107 @@ +== About texvc == + +texvc takes LaTeX-compatible equations and produces formatted output in +HTML, MathML, and (via LaTeX/dvips/ImageMagick) rasterized PNG images. +Input data is parsed and scrutinized for safety, and the output includes +an estimate of whether the code is simple enough that HTML rendering will +look acceptable. + +The program was written by Tomasz Wegrzanowski for use with MediaWiki; +it's included as part of the MediaWiki package (http://wikipedia.sf.net) +and is under the GPL license. + +Please report bugs at: http://bugzilla.wikimedia.org/ (under "MediaWiki") + +== Setup == + +=== Requirements === + +OCaml 3.06 or later is required to compile texvc; this can be acquired +from http://caml.inria.fr/ if your system doesn't have it available. + +The makefile requires GNU make. + +Rasterization is done via LaTeX, dvips, and ImageMagick. These need +to be installed and in the PATH: latex, dvips, convert + +To work properly with rendering non-ASCII Unicode characters, a +supplemental TeX package is needed (cjk-latex in Debian) + +=== Installation === + +Run 'make' (or 'gmake' if GNU make is not your default make). This should +produce the texvc executable. + +If you're using MediaWiki's install.php and have enabled $wgUseTeX in your +LocalSettings.php, the installer will try to copy texvc into place, in the +'math' subdirectory under where wiki.phtml is installed. + + +== Usage == + +Normally texvc is called from MediaWiki's Math.php modules and everything +Just Works. It can be run manually for testing or for use in another app. + +=== Command-line parameters === + + texvc <temp directory> <output directory> <TeX code> <encoding> + +Be sure to properly quote the TeX code! + +Example: + + texvc /home/wiki/tmp /home/wiki/math "y=x+2" iso-8859-1 + +=== Output format === + +Status codes and HTML/MathML transformations are returned on stdout. +A rasterized PNG file will be written to the output directory, named +for the MD5 hash code. + +texvc output format is like this: + +%5 ok, but not html or mathml + c%5%h ok, conservative html, no mathml + m%5%h ok, moderate html, no mathml + l%5%h ok, liberal html, no mathml + C%5%h\0%m ok, conservative html, with mathml + M%5%h\0%m ok, moderate html, with mathml + L%5%h\0%m ok, liberal html, with mathml + X%5%m ok, no html, with mathml + S syntax error + E lexing error + F%s unknown function %s + - other error + + \0 - null character + %5 - md5, 32 hex characters + %h - html code, without \0 characters + %m - mathml code, without \0 characters + + +== Troubleshooting == + +Unforunately, many error conditions with rasterization are not well reported. +texvc will return as though everything is successful, and the only obvious +sign of problems for the user is a big X on a wiki page where an equation +should be. + +Try running texvc from the command line to ensure that the software it relies +upon is all set up. + +Ensure that the temporary and math directories exist and can be written to by +the user account the web server runs under; if you don't control the server, +you may have to make them world-writable. + +== Hacking == + +Before you start hacking on the math package its good to know the workflow, +which is basically: + +1. texvc gets called by includes/Math.php (check out the line begining with "$cmd") +2. texvc does its magic, which is basically to check for invalid latex code. +3. texvc takes the user input if valid and creates a latex file containing it, see + get_preface in texutil.ml +4. latex(1) gets called to create a .dvi file, then a .ps file is created from the + .dvi file using dvips(1), and finally convert(1) creates a .png file from + the .ps file. See render.ml for this process (commenting out the removal of + the temporary file is useful for debugging). diff --git a/math/TODO b/math/TODO new file mode 100644 index 00000000..bd8d1f4f --- /dev/null +++ b/math/TODO @@ -0,0 +1,3 @@ +* It would be better if PNGs were transparent +* CJK support +* Documentation, in particular about instalation of Latex support for Unicode diff --git a/math/html.ml b/math/html.ml new file mode 100644 index 00000000..6a24b114 --- /dev/null +++ b/math/html.ml @@ -0,0 +1,119 @@ +open Render_info +open Tex +open Util + +exception Too_difficult_for_html +type context = CTX_NORMAL | CTX_IT | CTX_RM +type conservativeness_t = CONSERVATIVE | MODERATE | LIBERAL + +let conservativeness = ref CONSERVATIVE +let html_liberal () = conservativeness := LIBERAL +let html_moderate () = if !conservativeness = CONSERVATIVE then conservativeness := MODERATE else () + + +let new_ctx = function + FONTFORCE_IT -> CTX_IT + | FONTFORCE_RM -> CTX_RM +let font_render lit = function + (_, FONT_UFH) -> lit + | (_, FONT_UF) -> lit + | (CTX_IT,FONT_RTI) -> raise Too_difficult_for_html + | (_, FONT_RTI) -> lit + | (CTX_IT,FONT_RM) -> "<i>"^lit^"</i>" + | (_, FONT_RM) -> lit + | (CTX_RM,FONT_IT) -> lit + | (_, FONT_IT) -> "<i>"^lit^"</i>" + +let rec html_render_flat ctx = function + TEX_LITERAL (HTMLABLE (ft,_,sh))::r -> (html_liberal (); (font_render sh (ctx,ft))^html_render_flat ctx r) + | TEX_LITERAL (HTMLABLEC(ft,_,sh))::r -> (font_render sh (ctx,ft))^html_render_flat ctx r + | TEX_LITERAL (MHTMLABLEC(ft,_,sh,_,_))::r -> (font_render sh (ctx,ft))^html_render_flat ctx r + | TEX_LITERAL (HTMLABLEM(ft,_,sh))::r -> (html_moderate(); (font_render sh (ctx,ft))^html_render_flat ctx r) + | TEX_LITERAL (HTMLABLE_BIG (_,sh))::r -> (html_liberal (); sh^html_render_flat ctx r) + | TEX_FUN1hl (_,(f1,f2),a)::r -> f1^(html_render_flat ctx [a])^f2^html_render_flat ctx r + | TEX_FUN1hf (_,ff,a)::r -> (html_render_flat (new_ctx ff) [a])^html_render_flat ctx r + | TEX_DECLh (_,ff,a)::r -> (html_render_flat (new_ctx ff) a)^html_render_flat ctx r + | TEX_CURLY ls::r -> html_render_flat ctx (ls @ r) + | TEX_DQ (a,b)::r -> (html_liberal (); + let bs = html_render_flat ctx [b] in match html_render_size ctx a with + true, s -> raise Too_difficult_for_html + | false, s -> s^"<sub>"^bs^"</sub>")^html_render_flat ctx r + | TEX_UQ (a,b)::r -> (html_liberal (); + let bs = html_render_flat ctx [b] in match html_render_size ctx a with + true, s -> raise Too_difficult_for_html + | false, s -> s^"<sup>"^bs^"</sup>")^html_render_flat ctx r + | TEX_FQ (a,b,c)::r -> (html_liberal (); + (let bs = html_render_flat ctx [b] in let cs = html_render_flat ctx [c] in + match html_render_size ctx a with + true, s -> raise Too_difficult_for_html + | false, s -> s^"<sub>"^bs^"</sub><sup>"^cs^"</sup>")^html_render_flat ctx r) + | TEX_BOX (_,s)::r -> s^html_render_flat ctx r + | TEX_LITERAL (TEX_ONLY _)::_ -> raise Too_difficult_for_html + | TEX_FUN1 _::_ -> raise Too_difficult_for_html + | TEX_FUN2 _::_ -> raise Too_difficult_for_html + | TEX_FUN2h _::_ -> raise Too_difficult_for_html + | TEX_FUN2sq _::_ -> raise Too_difficult_for_html + | TEX_INFIX _::_ -> raise Too_difficult_for_html + | TEX_INFIXh _::_ -> raise Too_difficult_for_html + | TEX_MATRIX _::_ -> raise Too_difficult_for_html + | TEX_LR _::_ -> raise Too_difficult_for_html + | TEX_BIG _::_ -> raise Too_difficult_for_html + | [] -> "" +and html_render_size ctx = function + TEX_LITERAL (HTMLABLE_BIG (_,sh)) -> true,sh + | x -> false,html_render_flat ctx [x] + +let rec html_render_deep ctx = function + TEX_LITERAL (HTMLABLE (ft,_,sh))::r -> (html_liberal (); ("",(font_render sh (ctx,ft)),"")::html_render_deep ctx r) + | TEX_LITERAL (HTMLABLEM(ft,_,sh))::r -> (html_moderate(); ("",(font_render sh (ctx,ft)),"")::html_render_deep ctx r) + | TEX_LITERAL (HTMLABLEC(ft,_,sh))::r -> ("",(font_render sh (ctx,ft)),"")::html_render_deep ctx r + | TEX_LITERAL (MHTMLABLEC(ft,_,sh,_,_))::r -> ("",(font_render sh (ctx,ft)),"")::html_render_deep ctx r + | TEX_LITERAL (HTMLABLE_BIG (_,sh))::r -> (html_liberal (); ("",sh,"")::html_render_deep ctx r) + | TEX_FUN2h (_,f,a,b)::r -> (html_liberal (); (f a b)::html_render_deep ctx r) + | TEX_INFIXh (_,f,a,b)::r -> (html_liberal (); (f a b)::html_render_deep ctx r) + | TEX_CURLY ls::r -> html_render_deep ctx (ls @ r) + | TEX_DQ (a,b)::r -> (let bs = html_render_flat ctx [b] in match html_render_size ctx a with + true, s -> "","<font size='+2'>"^s^"</font>",bs + | false, s -> "",(s^"<sub>"^bs^"</sub>"),"")::html_render_deep ctx r + | TEX_UQ (a,b)::r -> (let bs = html_render_flat ctx [b] in match html_render_size ctx a with + true, s -> bs,"<font size='+2'>"^s^"</font>","" + | false, s -> "",(s^"<sup>"^bs^"</sup>"),"")::html_render_deep ctx r + | TEX_FQ (a,b,c)::r -> (html_liberal (); + (let bs = html_render_flat ctx [b] in let cs = html_render_flat ctx [c] in + match html_render_size ctx a with + true, s -> (cs,"<font size='+2'>"^s^"</font>",bs) + | false, s -> ("",(s^"<sub>"^bs^"</sub><sup>"^cs^"</sup>"),""))::html_render_deep ctx r) + | TEX_FUN1hl (_,(f1,f2),a)::r -> ("",f1,"")::(html_render_deep ctx [a]) @ ("",f2,"")::html_render_deep ctx r + | TEX_FUN1hf (_,ff,a)::r -> (html_render_deep (new_ctx ff) [a]) @ html_render_deep ctx r + | TEX_DECLh (_,ff,a)::r -> (html_render_deep (new_ctx ff) a) @ html_render_deep ctx r + | TEX_BOX (_,s)::r -> ("",s,"")::html_render_deep ctx r + | TEX_LITERAL (TEX_ONLY _)::_ -> raise Too_difficult_for_html + | TEX_FUN1 _::_ -> raise Too_difficult_for_html + | TEX_FUN2 _::_ -> raise Too_difficult_for_html + | TEX_FUN2sq _::_ -> raise Too_difficult_for_html + | TEX_INFIX _::_ -> raise Too_difficult_for_html + | TEX_MATRIX _::_ -> raise Too_difficult_for_html + | TEX_LR _::_ -> raise Too_difficult_for_html + | TEX_BIG _::_ -> raise Too_difficult_for_html + | [] -> [] + +let rec html_render_table = function + sf,u,d,("",a,"")::("",b,"")::r -> html_render_table (sf,u,d,(("",a^b,"")::r)) + | sf,u,d,(("",a,"") as c)::r -> html_render_table (c::sf,u,d,r) + | sf,u,d,((_,a,"") as c)::r -> html_render_table (c::sf,true,d,r) + | sf,u,d,(("",a,_) as c)::r -> html_render_table (c::sf,u,true,r) + | sf,u,d,((_,a,_) as c)::r -> html_render_table (c::sf,true,true,r) + | sf,false,false,[] -> mapjoin (function (u,m,d) -> m) (List.rev sf) + | sf,true,false,[] -> let ustr,mstr = List.fold_left (fun (us,ms) (u,m,d) -> (us^"<td>"^u^"</td>",ms^"<td>"^u^"</td>")) + ("","") (List.rev sf) in + "<table><tr align='center' valign='bottom'>" ^ ustr ^ "</tr><tr align='center'>" ^ mstr ^ "</tr></table>" + | sf,false,true,[] -> let mstr,dstr = List.fold_left (fun (ms,ds) (u,m,d) -> (ms^"<td>"^m^"</td>",ds^"<td>"^d^"</td>")) + ("","") (List.rev sf) in + "<table><tr align='center'>" ^ mstr ^ "</tr><tr align='center' valign='top'>" ^ dstr ^ "</tr></table>" + | sf,true,true,[] -> let ustr,mstr,dstr = List.fold_left (fun (us,ms,ds) (u,m,d) -> + (us^"<td>"^u^"</td>",ms^"<td>"^m^"</td>",ds^"<td>"^d^"</td>")) ("","","") (List.rev sf) in + "<table><tr align='center' valign='bottom'>" ^ ustr ^ "</tr><tr align='center'>" ^ mstr ^ "</tr><tr align='center' valign='top'>" ^ dstr ^ "</tr></table>" + +let html_render tree = html_render_table ([],false,false,html_render_deep CTX_NORMAL tree) + +let render tree = try Some (html_render tree) with _ -> None diff --git a/math/html.mli b/math/html.mli new file mode 100644 index 00000000..00b41cf4 --- /dev/null +++ b/math/html.mli @@ -0,0 +1,5 @@ +val render : Tex.t list -> string option +val html_render : Tex.t list -> string + +type conservativeness_t = CONSERVATIVE | MODERATE | LIBERAL +val conservativeness : conservativeness_t ref diff --git a/math/lexer.mll b/math/lexer.mll new file mode 100644 index 00000000..e5bb1ddf --- /dev/null +++ b/math/lexer.mll @@ -0,0 +1,93 @@ +{ + open Parser + open Render_info + open Tex +} +let space = [' ' '\t' '\n' '\r'] +let alpha = ['a'-'z' 'A'-'Z'] +let literal_id = ['a'-'z' 'A'-'Z'] +let literal_mn = ['0'-'9'] +let literal_uf_lt = [',' ':' ';' '?' '!' '\''] +let delimiter_uf_lt = ['(' ')' '.'] +let literal_uf_op = ['+' '-' '*' '='] +let delimiter_uf_op = ['/' '|'] +let boxchars = ['0'-'9' 'a'-'z' 'A'-'Z' '+' '-' '*' ',' '=' '(' ')' ':' '/' ';' '?' '.' '!' ' ' '\128'-'\255'] +let aboxchars = ['0'-'9' 'a'-'z' 'A'-'Z' '+' '-' '*' ',' '=' '(' ')' ':' '/' ';' '?' '.' '!' ' '] + +rule token = parse + space + { token lexbuf } + | "\\mbox" space * '{' aboxchars + '}' + { let str = Lexing.lexeme lexbuf in + let n = String.index str '{' + 1 in + BOX ("\\mbox", String.sub str n (String.length str - n - 1)) } + | "\\hbox" space * '{' aboxchars + '}' + { let str = Lexing.lexeme lexbuf in + let n = String.index str '{' + 1 in + BOX ("\\hbox", String.sub str n (String.length str - n - 1)) } + | "\\vbox" space * '{' aboxchars + '}' + { let str = Lexing.lexeme lexbuf in + let n = String.index str '{' + 1 in + BOX ("\\vbox", String.sub str n (String.length str - n - 1)) } + | "\\mbox" space * '{' boxchars + '}' + { let str = Lexing.lexeme lexbuf in + let n = String.index str '{' + 1 in + Texutil.tex_use_nonascii(); + BOX ("\\mbox", String.sub str n (String.length str - n - 1)) } + | "\\hbox" space * '{' boxchars + '}' + { let str = Lexing.lexeme lexbuf in + let n = String.index str '{' + 1 in + Texutil.tex_use_nonascii(); + BOX ("\\hbox", String.sub str n (String.length str - n - 1)) } + | "\\vbox" space * '{' boxchars + '}' + { let str = Lexing.lexeme lexbuf in + let n = String.index str '{' + 1 in + Texutil.tex_use_nonascii(); + BOX ("\\vbox", String.sub str n (String.length str - n - 1)) } + | literal_id { let str = Lexing.lexeme lexbuf in LITERAL (MHTMLABLEC (FONT_IT, str,str,MI,str)) } + | literal_mn { let str = Lexing.lexeme lexbuf in LITERAL (MHTMLABLEC (FONT_RM, str,str,MN,str)) } + | literal_uf_lt { let str = Lexing.lexeme lexbuf in LITERAL (HTMLABLEC (FONT_UFH, str,str)) } + | delimiter_uf_lt { let str = Lexing.lexeme lexbuf in DELIMITER (HTMLABLEC (FONT_UFH, str,str)) } + | "-" { let str = Lexing.lexeme lexbuf in LITERAL (MHTMLABLEC (FONT_UFH,"-"," − ",MO,str))} + | literal_uf_op { let str = Lexing.lexeme lexbuf in LITERAL (MHTMLABLEC (FONT_UFH, str," "^str^" ",MO,str)) } + | delimiter_uf_op { let str = Lexing.lexeme lexbuf in DELIMITER (MHTMLABLEC (FONT_UFH, str," "^str^" ",MO,str)) } + | "\\" alpha + { Texutil.find (Lexing.lexeme lexbuf) } + | "\\sqrt" space * "[" { FUN_AR1opt "\\sqrt" } + | "\\," { LITERAL (HTMLABLE (FONT_UF, "\\,"," ")) } + | "\\ " { LITERAL (HTMLABLE (FONT_UF, "\\ "," ")) } + | "\\;" { LITERAL (HTMLABLE (FONT_UF, "\\;"," ")) } + | "\\!" { LITERAL (TEX_ONLY "\\!") } + | "\\{" { DELIMITER (HTMLABLEC(FONT_UFH,"\\{","{")) } + | "\\}" { DELIMITER (HTMLABLEC(FONT_UFH,"\\}","}")) } + | "\\|" { DELIMITER (HTMLABLE (FONT_UFH,"\\|","||")) } + | "\\_" { LITERAL (HTMLABLEC(FONT_UFH,"\\_","_")) } + | "\\#" { LITERAL (HTMLABLE (FONT_UFH,"\\#","#")) } + | "\\%" { LITERAL (HTMLABLE (FONT_UFH,"\\%","%")) } + | "\\$" { LITERAL (HTMLABLE (FONT_UFH,"\\$","$")) } + | "&" { NEXT_CELL } + | "\\\\" { NEXT_ROW } + | "\\begin{matrix}" { Texutil.tex_use_ams(); BEGIN__MATRIX } + | "\\end{matrix}" { END__MATRIX } + | "\\begin{pmatrix}" { Texutil.tex_use_ams(); BEGIN_PMATRIX } + | "\\end{pmatrix}" { END_PMATRIX } + | "\\begin{bmatrix}" { Texutil.tex_use_ams(); BEGIN_BMATRIX } + | "\\end{bmatrix}" { END_BMATRIX } + | "\\begin{Bmatrix}" { Texutil.tex_use_ams(); BEGIN_BBMATRIX } + | "\\end{Bmatrix}" { END_BBMATRIX } + | "\\begin{vmatrix}" { Texutil.tex_use_ams(); BEGIN_VMATRIX } + | "\\end{vmatrix}" { END_VMATRIX } + | "\\begin{Vmatrix}" { Texutil.tex_use_ams(); BEGIN_VVMATRIX } + | "\\end{Vmatrix}" { END_VVMATRIX } + | "\\begin{cases}" { Texutil.tex_use_ams(); BEGIN_CASES } + | "\\end{cases}" { END_CASES } + | '>' { LITERAL (HTMLABLEC(FONT_UFH,">"," > ")) } + | '<' { LITERAL (HTMLABLEC(FONT_UFH,"<"," < ")) } + | '%' { LITERAL (HTMLABLEC(FONT_UFH,"\\%","%")) } + | '$' { LITERAL (HTMLABLEC(FONT_UFH,"\\$","$")) } + | '~' { LITERAL (HTMLABLE (FONT_UF, "~"," ")) } + | '[' { DELIMITER (HTMLABLEC(FONT_UFH,"[","[")) } + | ']' { SQ_CLOSE } + | '{' { CURLY_OPEN } + | '}' { CURLY_CLOSE } + | '^' { SUP } + | '_' { SUB } + | eof { EOF } diff --git a/math/mathml.ml b/math/mathml.ml new file mode 100644 index 00000000..b6c76af2 --- /dev/null +++ b/math/mathml.ml @@ -0,0 +1,20 @@ +open Tex +open Render_info + +type t = TREE_MN of string | TREE_MO of string | TREE_MI of string + +let rec make_mathml_tree = function + TREE_MN a::otr,TEX_LITERAL(MHTMLABLEC(_,_,_,MN,b))::itr -> make_mathml_tree(TREE_MN (a^b)::otr,itr) + | otr,TEX_LITERAL(MHTMLABLEC(_,_,_,MN,a))::itr -> make_mathml_tree(TREE_MN a::otr,itr) + | otr,TEX_LITERAL(MHTMLABLEC(_,_,_,MO,a))::itr -> make_mathml_tree(TREE_MO a::otr,itr) + | otr,TEX_LITERAL(MHTMLABLEC(_,_,_,MI,a))::itr -> make_mathml_tree(TREE_MI a::otr,itr) + | otr,TEX_CURLY(crl)::itr -> make_mathml_tree(otr,crl@itr) + | otr,[] -> List.rev otr + | _ -> failwith "failed to render mathml" + +let render_mathml_tree = function + TREE_MN s -> "<mn>"^s^"</mn>" + | TREE_MI s -> "<mi>"^s^"</mi>" + | TREE_MO s -> "<mo>"^s^"</mo>" + +let render tree = try Some (Util.mapjoin render_mathml_tree (make_mathml_tree ([],tree))) with _ -> None diff --git a/math/mathml.mli b/math/mathml.mli new file mode 100644 index 00000000..fcc2cd4c --- /dev/null +++ b/math/mathml.mli @@ -0,0 +1 @@ +val render : Tex.t list -> string option diff --git a/math/parser.mly b/math/parser.mly new file mode 100644 index 00000000..4787db37 --- /dev/null +++ b/math/parser.mly @@ -0,0 +1,103 @@ +%{ + open Tex + open Render_info + + let sq_close_ri = HTMLABLEC(FONT_UFH,"]", "]") +%} +%token <Render_info.t> LITERAL DELIMITER +%token <string> FUN_AR2 FUN_INFIX FUN_AR1 DECL FUN_AR1opt BIG +%token <string*string> BOX +%token <string*(string*string)> FUN_AR1hl +%token <string*Render_info.font_force> FUN_AR1hf DECLh +%token <string*(Tex.t->Tex.t->string*string*string)> FUN_AR2h +%token <string*(Tex.t list->Tex.t list->string*string*string)> FUN_INFIXh +%token EOF CURLY_OPEN CURLY_CLOSE SUB SUP SQ_CLOSE NEXT_CELL NEXT_ROW +%token BEGIN__MATRIX BEGIN_PMATRIX BEGIN_BMATRIX BEGIN_BBMATRIX BEGIN_VMATRIX BEGIN_VVMATRIX BEGIN_CASES +%token END__MATRIX END_PMATRIX END_BMATRIX END_BBMATRIX END_VMATRIX END_VVMATRIX END_CASES +%token LEFT RIGHT + +%type <Tex.t list> tex_expr +%start tex_expr + +%% +tex_expr: + expr EOF { $1 } + | ne_expr FUN_INFIX ne_expr EOF + { [TEX_INFIX($2,$1,$3)] } + | ne_expr FUN_INFIXh ne_expr EOF + { let t,h=$2 in [TEX_INFIXh(t,h,$1,$3)] } +expr: + /* */ { [] } + | ne_expr { $1 } +ne_expr: + lit_aq expr { $1 :: $2 } + | litsq_aq expr { $1 :: $2 } + | DECLh expr { let t,h = $1 in [TEX_DECLh(t,h,$2)] } +litsq_aq: + litsq_zq { $1 } + | litsq_dq { let base,downi = $1 in TEX_DQ(base,downi) } + | litsq_uq { let base,upi = $1 in TEX_UQ(base,upi)} + | litsq_fq { $1 } +litsq_fq: + litsq_dq SUP lit { let base,downi = $1 in TEX_FQ(base,downi,$3) } + | litsq_uq SUB lit { let base,upi = $1 in TEX_FQ(base,$3,upi) } +litsq_uq: + litsq_zq SUP lit { $1,$3 } +litsq_dq: + litsq_zq SUB lit { $1,$3 } +litsq_zq: + | SQ_CLOSE { TEX_LITERAL sq_close_ri } +expr_nosqc: + /* */ { [] } + | lit_aq expr_nosqc { $1 :: $2 } +lit_aq: + lit { $1 } + | lit_dq { let base,downi = $1 in TEX_DQ(base,downi) } + | lit_uq { let base,upi = $1 in TEX_UQ(base,upi)} + | lit_fq { $1 } +lit_fq: + lit_dq SUP lit { let base,downi = $1 in TEX_FQ(base,downi,$3) } + | lit_uq SUB lit { let base,upi = $1 in TEX_FQ(base,$3,upi) } +lit_uq: + lit SUP lit { $1,$3 } +lit_dq: + lit SUB lit { $1,$3 } +left: + LEFT DELIMITER { $2 } + | LEFT SQ_CLOSE { sq_close_ri } +right: + RIGHT DELIMITER { $2 } + | RIGHT SQ_CLOSE { sq_close_ri } +lit: + LITERAL { TEX_LITERAL $1 } + | DELIMITER { TEX_LITERAL $1 } + | BIG DELIMITER { TEX_BIG ($1,$2) } + | BIG SQ_CLOSE { TEX_BIG ($1,sq_close_ri) } + | left expr right { TEX_LR ($1,$3,$2) } + | FUN_AR1 lit { TEX_FUN1($1,$2) } + | FUN_AR1hl lit { let t,h=$1 in TEX_FUN1hl(t,h,$2) } + | FUN_AR1hf lit { let t,h=$1 in TEX_FUN1hf(t,h,$2) } + | FUN_AR1opt expr_nosqc SQ_CLOSE lit { TEX_FUN2sq($1,TEX_CURLY $2,$4) } + | FUN_AR2 lit lit { TEX_FUN2($1,$2,$3) } + | FUN_AR2h lit lit { let t,h=$1 in TEX_FUN2h(t,h,$2,$3) } + | BOX { let bt,s = $1 in TEX_BOX (bt,s) } + | CURLY_OPEN expr CURLY_CLOSE + { TEX_CURLY $2 } + | CURLY_OPEN ne_expr FUN_INFIX ne_expr CURLY_CLOSE + { TEX_INFIX($3,$2,$4) } + | CURLY_OPEN ne_expr FUN_INFIXh ne_expr CURLY_CLOSE + { let t,h=$3 in TEX_INFIXh(t,h,$2,$4) } + | BEGIN__MATRIX matrix END__MATRIX { TEX_MATRIX ("matrix", $2) } + | BEGIN_PMATRIX matrix END_PMATRIX { TEX_MATRIX ("pmatrix", $2) } + | BEGIN_BMATRIX matrix END_BMATRIX { TEX_MATRIX ("bmatrix", $2) } + | BEGIN_BBMATRIX matrix END_BBMATRIX { TEX_MATRIX ("Bmatrix", $2) } + | BEGIN_VMATRIX matrix END_VMATRIX { TEX_MATRIX ("vmatrix", $2) } + | BEGIN_VVMATRIX matrix END_VVMATRIX { TEX_MATRIX ("Vmatrix", $2) } + | BEGIN_CASES matrix END_CASES { TEX_MATRIX ("cases", $2) } +matrix: + line { [$1] } + | line NEXT_ROW matrix { $1::$3 } +line: + expr { [$1] } + | expr NEXT_CELL line { $1::$3 } +;; diff --git a/math/render.ml b/math/render.ml new file mode 100644 index 00000000..f070a91e --- /dev/null +++ b/math/render.ml @@ -0,0 +1,33 @@ +let cmd_dvips tmpprefix = "dvips -R -E " ^ tmpprefix ^ ".dvi -f >" ^ tmpprefix ^ ".ps" +let cmd_latex tmpprefix = "latex " ^ tmpprefix ^ ".tex >/dev/null" +(* Putting -transparent white in converts arguments will sort-of give you transperancy *) +let cmd_convert tmpprefix finalpath = "convert -quality 100 -density 120 " ^ tmpprefix ^ ".ps " ^ finalpath ^ " >/dev/null 2>/dev/null" + +exception ExternalCommandFailure of string + +let render tmppath finalpath outtex md5 = + let tmpprefix0 = (string_of_int (Unix.getpid ()))^"_"^md5 in + let tmpprefix = (tmppath^"/"^tmpprefix0) in + let unlink_all () = + begin + (* Commenting this block out will aid in debugging *) + Sys.remove (tmpprefix ^ ".dvi"); + Sys.remove (tmpprefix ^ ".aux"); + Sys.remove (tmpprefix ^ ".log"); + Sys.remove (tmpprefix ^ ".tex"); + Sys.remove (tmpprefix ^ ".ps"); + end in + let f = (Util.open_out_unless_exists (tmpprefix ^ ".tex")) in + begin + output_string f (Texutil.get_preface ()); + output_string f outtex; + output_string f (Texutil.get_footer ()); + close_out f; + if Util.run_in_other_directory tmppath (cmd_latex tmpprefix0) != 0 + then (unlink_all (); raise (ExternalCommandFailure "latex")) + else if (Sys.command (cmd_dvips tmpprefix) != 0) + then (unlink_all (); raise (ExternalCommandFailure "dvips")) + else if (Sys.command (cmd_convert tmpprefix (finalpath^"/"^md5^".png")) != 0) + then (unlink_all (); raise (ExternalCommandFailure "convert")) + else unlink_all () + end diff --git a/math/render_info.mli b/math/render_info.mli new file mode 100644 index 00000000..d5e7fde9 --- /dev/null +++ b/math/render_info.mli @@ -0,0 +1,20 @@ +type font_force = + FONTFORCE_IT + | FONTFORCE_RM +type font_class = + FONT_IT (* IT default, may be forced to be RM *) + | FONT_RM (* RM default, may be forced to be IT *) + | FONT_UF (* not affected by IT/RM setting *) + | FONT_RTI (* RM - any, IT - not available in HTML *) + | FONT_UFH (* in TeX UF, in HTML RM *) +type math_class = + MN + | MI + | MO +type t = + HTMLABLEC of font_class * string * string + | HTMLABLEM of font_class * string * string + | HTMLABLE of font_class * string * string + | MHTMLABLEC of font_class * string * string * math_class * string + | HTMLABLE_BIG of string * string + | TEX_ONLY of string diff --git a/math/tex.mli b/math/tex.mli new file mode 100644 index 00000000..9e6013df --- /dev/null +++ b/math/tex.mli @@ -0,0 +1,19 @@ +type t = + TEX_LITERAL of Render_info.t + | TEX_CURLY of t list + | TEX_FQ of t * t * t + | TEX_DQ of t * t + | TEX_UQ of t * t + | TEX_LR of Render_info.t * Render_info.t * t list + | TEX_BOX of string * string + | TEX_BIG of string * Render_info.t + | TEX_FUN1 of string * t + | TEX_FUN2 of string * t * t + | TEX_INFIX of string * t list * t list + | TEX_FUN2sq of string * t * t + | TEX_FUN1hl of string * (string * string) * t + | TEX_FUN1hf of string * Render_info.font_force * t + | TEX_FUN2h of string * (t -> t -> string * string * string) * t * t + | TEX_INFIXh of string * (t list -> t list -> string * string * string) * t list * t list + | TEX_MATRIX of string * t list list list + | TEX_DECLh of string * Render_info.font_force * t list diff --git a/math/texutil.ml b/math/texutil.ml new file mode 100644 index 00000000..f7678e34 --- /dev/null +++ b/math/texutil.ml @@ -0,0 +1,482 @@ +open Parser +open Render_info +open Tex +open Util + +let tex_part = function + HTMLABLE (_,t,_) -> t + | HTMLABLEM (_,t,_) -> t + | HTMLABLEC (_,t,_) -> t + | MHTMLABLEC (_,t,_,_,_) -> t + | HTMLABLE_BIG (t,_) -> t + | TEX_ONLY t -> t +let rec render_tex = function + TEX_FQ (a,b,c) -> (render_tex a) ^ "_{" ^ (render_tex b) ^ "}^{" ^ (render_tex c) ^ "}" + | TEX_DQ (a,b) -> (render_tex a) ^ "_{" ^ (render_tex b) ^ "}" + | TEX_UQ (a,b) -> (render_tex a) ^ "^{" ^ (render_tex b) ^ "}" + | TEX_LITERAL s -> tex_part s + | TEX_FUN1 (f,a) -> "{" ^ f ^ " " ^ (render_tex a) ^ "}" + | TEX_FUN1hl (f,_,a) -> "{" ^ f ^ " " ^ (render_tex a) ^ "}" + | TEX_FUN1hf (f,_,a) -> "{" ^ f ^ " " ^ (render_tex a) ^ "}" + | TEX_DECLh (f,_,a) -> "{" ^ f ^ "{" ^ (mapjoin render_tex a) ^ "}}" + | TEX_FUN2 (f,a,b) -> "{" ^ f ^ " " ^ (render_tex a) ^ (render_tex b) ^ "}" + | TEX_FUN2h (f,_,a,b) -> "{" ^ f ^ " " ^ (render_tex a) ^ (render_tex b) ^ "}" + | TEX_FUN2sq (f,a,b) -> "{" ^ f ^ "[ " ^ (render_tex a) ^ "]" ^ (render_tex b) ^ "}" + | TEX_CURLY (tl) -> "{" ^ (mapjoin render_tex tl) ^ "}" + | TEX_INFIX (s,ll,rl) -> "{" ^ (mapjoin render_tex ll) ^ " " ^ s ^ "" ^ (mapjoin render_tex rl) ^ "}" + | TEX_INFIXh (s,_,ll,rl) -> "{" ^ (mapjoin render_tex ll) ^ " " ^ s ^ "" ^ (mapjoin render_tex rl) ^ "}" + | TEX_BOX (bt,s) -> "{"^bt^"{" ^ s ^ "}}" + | TEX_BIG (bt,d) -> "{"^bt^(tex_part d)^"}" + | TEX_MATRIX (t,rows) -> "{\\begin{"^t^"}"^(mapjoine "\\\\" (mapjoine "&" (mapjoin render_tex)) rows)^"\\end{"^t^"}}" + | TEX_LR (l,r,tl) -> "\\left "^(tex_part l)^(mapjoin render_tex tl)^"\\right "^(tex_part r) + +(* Dynamic loading*) +type encoding_t = LATIN1 | LATIN2 | UTF8 + +let modules_ams = ref false +let modules_nonascii = ref false +let modules_encoding = ref UTF8 +let modules_color = ref false + +let tex_use_ams () = modules_ams := true +let tex_use_nonascii () = modules_nonascii := true +let tex_use_color () = modules_color := true +let tex_mod_reset () = (modules_ams := false; modules_nonascii := false; modules_encoding := UTF8; modules_color := false) + +let get_encoding = function + UTF8 -> "\\usepackage{ucs}\n\\usepackage[utf8]{inputenc}\n" + | LATIN1 -> "\\usepackage[latin1]{inputenc}\n" + | LATIN2 -> "\\usepackage[latin2]{inputenc}\n" + +let get_preface () = "\\nonstopmode\n\\documentclass[12pt]{article}\n" ^ + (if !modules_nonascii then get_encoding !modules_encoding else "") ^ + (if !modules_ams then "\\usepackage{amsmath}\n\\usepackage{amsfonts}\n\\usepackage{amssymb}\n" else "") ^ + (if !modules_color then "\\usepackage[dvips,usenames]{color}\n" else "") ^ + "\\pagestyle{empty}\n\\begin{document}\n$$\n" +let get_footer () = "\n$$\n\\end{document}\n" + +let set_encoding = function + "ISO-8859-1" -> modules_encoding := LATIN1 + | "iso-8859-1" -> modules_encoding := LATIN1 + | "ISO-8859-2" -> modules_encoding := LATIN2 + | _ -> modules_encoding := UTF8 + +(* Turn that into hash table lookup *) +exception Illegal_tex_function of string + +let find = function + "\\alpha" -> LITERAL (HTMLABLEC (FONT_UF, "\\alpha ", "α")) + | "\\Alpha" -> LITERAL (HTMLABLEC (FONT_RTI, "A", "Α")) + | "\\beta" -> LITERAL (HTMLABLEC (FONT_UF, "\\beta ", "β")) + | "\\Beta" -> LITERAL (HTMLABLEC (FONT_RTI, "B", "Β")) + | "\\gamma" -> LITERAL (HTMLABLEC (FONT_UF, "\\gamma ", "γ")) + | "\\Gamma" -> LITERAL (HTMLABLEC (FONT_RTI, "\\Gamma ", "Γ")) + | "\\delta" -> LITERAL (HTMLABLEC (FONT_UF, "\\delta ", "δ")) + | "\\Delta" -> LITERAL (HTMLABLEC (FONT_RTI, "\\Delta ", "Δ")) + | "\\epsilon" -> LITERAL (HTMLABLEC (FONT_UF, "\\epsilon ", "ε")) + | "\\Epsilon" -> LITERAL (HTMLABLEC (FONT_RTI, "E", "Ε")) + | "\\varepsilon" -> LITERAL (TEX_ONLY "\\varepsilon ") + | "\\zeta" -> LITERAL (HTMLABLEC (FONT_UF, "\\zeta ", "ζ")) + | "\\Zeta" -> LITERAL (HTMLABLEC (FONT_RTI, "Z", "Ζ")) + | "\\eta" -> LITERAL (HTMLABLEC (FONT_UF, "\\eta ", "η")) + | "\\Eta" -> LITERAL (HTMLABLEC (FONT_RTI, "H", "Η")) + | "\\theta" -> LITERAL (HTMLABLEC (FONT_UF, "\\theta ", "θ")) + | "\\Theta" -> LITERAL (HTMLABLEC (FONT_RTI, "\\Theta ", "Θ")) + | "\\vartheta" -> LITERAL (HTMLABLE (FONT_UF, "\\vartheta ", "ϑ")) + | "\\thetasym" -> LITERAL (HTMLABLE (FONT_UF, "\\vartheta ", "ϑ")) + | "\\iota" -> LITERAL (HTMLABLEC (FONT_UF, "\\iota ", "ι")) + | "\\Iota" -> LITERAL (HTMLABLEC (FONT_RTI, "I", "Ι")) + | "\\kappa" -> LITERAL (HTMLABLEC (FONT_UF, "\\kappa ", "κ")) + | "\\Kappa" -> LITERAL (HTMLABLEC (FONT_RTI, "K", "Κ")) + | "\\lambda" -> LITERAL (HTMLABLEC (FONT_UF, "\\lambda ", "λ")) + | "\\Lambda" -> LITERAL (HTMLABLEC (FONT_RTI, "\\Lambda ", "Λ")) + | "\\mu" -> LITERAL (HTMLABLEC (FONT_UF, "\\mu ", "μ")) + | "\\Mu" -> LITERAL (HTMLABLEC (FONT_RTI, "M", "Μ")) + | "\\nu" -> LITERAL (HTMLABLEC (FONT_UF, "\\nu ", "ν")) + | "\\Nu" -> LITERAL (HTMLABLEC (FONT_RTI, "N", "Ν")) + | "\\pi" -> LITERAL (HTMLABLEC (FONT_UF, "\\pi ", "π")) + | "\\Pi" -> LITERAL (HTMLABLEC (FONT_RTI, "\\Pi ", "Π")) + | "\\varpi" -> LITERAL (TEX_ONLY "\\varpi ") + | "\\rho" -> LITERAL (HTMLABLEC (FONT_UF, "\\rho ", "ρ")) + | "\\Rho" -> LITERAL (HTMLABLEC (FONT_RTI, "P", "Ρ")) + | "\\varrho" -> LITERAL (TEX_ONLY "\\varrho ") + | "\\sim" -> LITERAL (HTMLABLEC (FONT_UF, "\\sim ", "˜")) + | "\\sigma" -> LITERAL (HTMLABLEC (FONT_UF, "\\sigma ", "σ")) + | "\\Sigma" -> LITERAL (HTMLABLEC (FONT_RTI, "\\Sigma ", "Σ")) + | "\\varsigma" -> LITERAL (TEX_ONLY "\\varsigma ") + | "\\tau" -> LITERAL (HTMLABLEC (FONT_UF, "\\tau ", "τ")) + | "\\Tau" -> LITERAL (HTMLABLEC (FONT_RTI, "T", "Τ")) + | "\\upsilon" -> LITERAL (HTMLABLEC (FONT_UF, "\\upsilon ", "υ")) + | "\\Upsilon" -> LITERAL (HTMLABLEC (FONT_RTI, "\\Upsilon ", "Υ")) + | "\\phi" -> LITERAL (HTMLABLEC (FONT_UF, "\\phi ", "φ")) + | "\\Phi" -> LITERAL (HTMLABLEC (FONT_RTI, "\\Phi ", "Φ")) + | "\\varphi" -> LITERAL (TEX_ONLY "\\varphi ") + | "\\chi" -> LITERAL (HTMLABLEC (FONT_UF, "\\chi ", "χ")) + | "\\Chi" -> LITERAL (HTMLABLEC (FONT_RTI, "X", "Χ")) + | "\\psi" -> LITERAL (HTMLABLEC (FONT_UF, "\\psi ", "ψ")) + | "\\Psi" -> LITERAL (HTMLABLEC (FONT_RTI, "\\Psi ", "Ψ")) + | "\\omega" -> LITERAL (HTMLABLEC (FONT_UF, "\\omega ", "ω")) + | "\\Omega" -> LITERAL (HTMLABLEC (FONT_RTI, "\\Omega ", "Ω")) + | "\\xi" -> LITERAL (HTMLABLEC (FONT_UF, "\\xi ", "ξ")) + | "\\Xi" -> LITERAL (HTMLABLEC (FONT_RTI, "\\Xi ", "Ξ")) + | "\\aleph" -> LITERAL (HTMLABLE (FONT_UF, "\\aleph ", "ℵ")) + | "\\alef" -> LITERAL (HTMLABLE (FONT_UF, "\\aleph ", "ℵ")) + | "\\alefsym" -> LITERAL (HTMLABLE (FONT_UF, "\\aleph ", "ℵ")) + | "\\larr" -> LITERAL (HTMLABLEM (FONT_UF, "\\leftarrow ", "←")) + | "\\leftarrow" -> LITERAL (HTMLABLEM (FONT_UF, "\\leftarrow ", "←")) + | "\\rarr" -> LITERAL (HTMLABLEM (FONT_UF, "\\rightarrow ", "→")) + | "\\to" -> LITERAL (HTMLABLEM (FONT_UF, "\\to ", "→")) + | "\\gets" -> LITERAL (HTMLABLEM (FONT_UF, "\\gets ", "←")) + | "\\rightarrow" -> LITERAL (HTMLABLEM (FONT_UF, "\\rightarrow ", "→")) + | "\\longleftarrow" -> LITERAL (HTMLABLE (FONT_UF, "\\longleftarrow ", "←")) + | "\\longrightarrow" -> LITERAL (HTMLABLE (FONT_UF, "\\longrightarrow ", "→")) + | "\\Larr" -> LITERAL (HTMLABLE (FONT_UF, "\\Leftarrow ", "⇐")) + | "\\lArr" -> LITERAL (HTMLABLE (FONT_UF, "\\Leftarrow ", "⇐")) + | "\\Leftarrow" -> LITERAL (HTMLABLE (FONT_UF, "\\Leftarrow ", "⇐")) + | "\\Rarr" -> LITERAL (HTMLABLE (FONT_UF, "\\Rightarrow ", "⇒")) + | "\\rArr" -> LITERAL (HTMLABLE (FONT_UF, "\\Rightarrow ", "⇒")) + | "\\Rightarrow" -> LITERAL (HTMLABLEM (FONT_UF, "\\Rightarrow ", "⇒")) + | "\\mapsto" -> LITERAL (HTMLABLE (FONT_UF, "\\mapsto ", "→")) + | "\\longmapsto" -> LITERAL (HTMLABLE (FONT_UF, "\\longmapsto ", "→")) + | "\\Longleftarrow" -> LITERAL (HTMLABLE (FONT_UF, "\\Longleftarrow ", "⇐")) + | "\\Longrightarrow" -> LITERAL (HTMLABLE (FONT_UF, "\\Longrightarrow ", "⇒")) + | "\\uarr" -> DELIMITER (HTMLABLEM (FONT_UF, "\\uparrow ", "↑")) + | "\\uparrow" -> DELIMITER (HTMLABLEM (FONT_UF, "\\uparrow ", "↑")) + | "\\uArr" -> DELIMITER (HTMLABLE (FONT_UF, "\\Uparrow ", "⇑")) + | "\\Uarr" -> DELIMITER (HTMLABLE (FONT_UF, "\\Uparrow ", "⇑")) + | "\\Uparrow" -> DELIMITER (HTMLABLE (FONT_UF, "\\Uparrow ", "⇑")) + | "\\darr" -> DELIMITER (HTMLABLEM (FONT_UF, "\\downarrow ", "↓")) + | "\\downarrow" -> DELIMITER (HTMLABLEM (FONT_UF, "\\downarrow ", "↓")) + | "\\dArr" -> DELIMITER (HTMLABLE (FONT_UF, "\\Downarrow ", "⇓")) + | "\\Darr" -> DELIMITER (HTMLABLE (FONT_UF, "\\Downarrow ", "⇓")) + | "\\Downarrow" -> DELIMITER (HTMLABLE (FONT_UF, "\\Downarrow ", "⇓")) + | "\\updownarrow" -> DELIMITER (TEX_ONLY "\\updownarrow ") + | "\\Updownarrow" -> DELIMITER (TEX_ONLY "\\Updownarrow ") + | "\\leftrightarrow" -> LITERAL (HTMLABLE (FONT_UF, "\\leftrightarrow ", "↔")) + | "\\lrarr" -> LITERAL (HTMLABLE (FONT_UF, "\\leftrightarrow ", "↔")) + | "\\harr" -> LITERAL (HTMLABLE (FONT_UF, "\\leftrightarrow ", "↔")) + | "\\Leftrightarrow" -> LITERAL (HTMLABLE (FONT_UF, "\\Leftrightarrow ", "⇔")) + | "\\Lrarr" -> LITERAL (HTMLABLE (FONT_UF, "\\Leftrightarrow ", "⇔")) + | "\\Harr" -> LITERAL (HTMLABLE (FONT_UF, "\\Leftrightarrow ", "⇔")) + | "\\lrArr" -> LITERAL (HTMLABLE (FONT_UF, "\\Leftrightarrow ", "⇔")) + | "\\hAar" -> LITERAL (HTMLABLE (FONT_UF, "\\Leftrightarrow ", "⇔")) + | "\\Longleftrightarrow"->LITERAL (HTMLABLE (FONT_UF, "\\Longleftrightarrow ", "↔")) + | "\\iff" -> LITERAL (HTMLABLE (FONT_UF, "\\iff ", "↔")) + | "\\ll" -> LITERAL (TEX_ONLY "\\ll ") + | "\\gg" -> LITERAL (TEX_ONLY "\\gg ") + | "\\div" -> LITERAL (TEX_ONLY "\\div ") + | "\\searrow" -> LITERAL (TEX_ONLY "\\searrow ") + | "\\nearrow" -> LITERAL (TEX_ONLY "\\nearrow ") + | "\\swarrow" -> LITERAL (TEX_ONLY "\\swarrow ") + | "\\nwarrow" -> LITERAL (TEX_ONLY "\\nwarrow ") + | "\\sim" -> LITERAL (TEX_ONLY "\\sim ") + | "\\simeq" -> LITERAL (TEX_ONLY "\\simeq ") + | "\\star" -> LITERAL (TEX_ONLY "\\star ") + | "\\ell" -> LITERAL (TEX_ONLY "\\ell ") + | "\\P" -> LITERAL (TEX_ONLY "\\P ") + | "\\smile" -> LITERAL (TEX_ONLY "\\smile ") + | "\\frown" -> LITERAL (TEX_ONLY "\\frown ") + | "\\bigcap" -> LITERAL (TEX_ONLY "\\bigcap ") + | "\\bigodot" -> LITERAL (TEX_ONLY "\\bigodot ") + | "\\bigcup" -> LITERAL (TEX_ONLY "\\bigcup ") + | "\\bigotimes" -> LITERAL (TEX_ONLY "\\bigotimes ") + | "\\coprod" -> LITERAL (TEX_ONLY "\\coprod ") + | "\\bigsqcup" -> LITERAL (TEX_ONLY "\\bigsqcup ") + | "\\bigoplus" -> LITERAL (TEX_ONLY "\\bigoplus ") + | "\\bigvee" -> LITERAL (TEX_ONLY "\\bigvee ") + | "\\biguplus" -> LITERAL (TEX_ONLY "\\biguplus ") + | "\\oint" -> LITERAL (TEX_ONLY "\\oint ") + | "\\bigwedge" -> LITERAL (TEX_ONLY "\\bigwedge ") + | "\\models" -> LITERAL (TEX_ONLY "\\models ") + | "\\vdash" -> LITERAL (TEX_ONLY "\\vdash ") + | "\\triangle" -> LITERAL (TEX_ONLY "\\triangle ") + | "\\bowtie" -> LITERAL (TEX_ONLY "\\bowtie ") + | "\\wr" -> LITERAL (TEX_ONLY "\\wr ") + | "\\triangleleft" -> LITERAL (TEX_ONLY "\\triangleleft ") + | "\\triangleright" -> LITERAL (TEX_ONLY "\\triangleright ") + | "\\textvisiblespace" -> LITERAL (TEX_ONLY "\\textvisiblespace ") + | "\\ker" -> LITERAL (TEX_ONLY "\\ker ") + | "\\lim" -> LITERAL (TEX_ONLY "\\lim ") + | "\\limsup" -> LITERAL (TEX_ONLY "\\limsup ") + | "\\liminf" -> LITERAL (TEX_ONLY "\\liminf ") + | "\\sup" -> LITERAL (TEX_ONLY "\\sup ") + | "\\Pr" -> LITERAL (TEX_ONLY "\\Pr ") + | "\\hom" -> LITERAL (TEX_ONLY "\\hom ") + | "\\arg" -> LITERAL (TEX_ONLY "\\arg ") + | "\\dim" -> LITERAL (TEX_ONLY "\\dim ") + | "\\inf" -> LITERAL (TEX_ONLY "\\inf ") + | "\\circ" -> LITERAL (TEX_ONLY "\\circ ") + | "\\hbar" -> LITERAL (TEX_ONLY "\\hbar ") + | "\\imath" -> LITERAL (TEX_ONLY "\\imath ") + | "\\lnot" -> LITERAL (TEX_ONLY "\\lnot ") + | "\\hookrightarrow" -> LITERAL (TEX_ONLY "\\hookrightarrow ") + | "\\hookleftarrow" -> LITERAL (TEX_ONLY "\\hookleftarrow ") + | "\\mp" -> LITERAL (TEX_ONLY "\\mp ") + | "\\approx" -> LITERAL (TEX_ONLY "\\approx ") + | "\\propto" -> LITERAL (TEX_ONLY "\\propto ") + | "\\flat" -> LITERAL (TEX_ONLY "\\flat ") + | "\\sharp" -> LITERAL (TEX_ONLY "\\sharp ") + | "\\natural" -> LITERAL (TEX_ONLY "\\natural ") + | "\\int" -> LITERAL (HTMLABLE_BIG ("\\int ", "∫")) + | "\\sum" -> LITERAL (HTMLABLE_BIG ("\\sum ", "∑")) + | "\\prod" -> LITERAL (HTMLABLE_BIG ("\\prod ", "∏")) + | "\\vdots" -> LITERAL (TEX_ONLY "\\vdots ") + | "\\limits" -> LITERAL (TEX_ONLY "\\limits ") + | "\\nolimits" -> LITERAL (TEX_ONLY "\\nolimits ") + | "\\top" -> LITERAL (TEX_ONLY "\\top ") + | "\\sin" -> LITERAL (HTMLABLEC(FONT_UFH,"\\sin ","sin")) + | "\\cos" -> LITERAL (HTMLABLEC(FONT_UFH,"\\cos ","cos")) + | "\\sinh" -> LITERAL (HTMLABLEC(FONT_UFH,"\\sinh ","sinh")) + | "\\cosh" -> LITERAL (HTMLABLEC(FONT_UFH,"\\cosh ","cosh")) + | "\\tan" -> LITERAL (HTMLABLEC(FONT_UFH,"\\tan ","tan")) + | "\\tanh" -> LITERAL (HTMLABLEC(FONT_UFH,"\\tanh ","tanh")) + | "\\sec" -> LITERAL (HTMLABLEC(FONT_UFH,"\\sec ","sec")) + | "\\csc" -> LITERAL (HTMLABLEC(FONT_UFH,"\\csc ","csc")) + | "\\arcsin" -> LITERAL (HTMLABLEC(FONT_UFH,"\\arcsin ","arcsin")) + | "\\arctan" -> LITERAL (HTMLABLEC(FONT_UFH,"\\arctan ","arctan")) + | "\\arccos" -> (tex_use_ams (); LITERAL (HTMLABLEC(FONT_UFH,"\\mathop{\\mathrm{arccos}}","arccos"))) + | "\\arccot" -> (tex_use_ams (); LITERAL (HTMLABLEC(FONT_UFH,"\\mathop{\\mathrm{arccot}}","arccot"))) + | "\\arcsec" -> (tex_use_ams (); LITERAL (HTMLABLEC(FONT_UFH,"\\mathop{\\mathrm{arcsec}}","arcsec"))) + | "\\arccsc" -> (tex_use_ams (); LITERAL (HTMLABLEC(FONT_UFH,"\\mathop{\\mathrm{arccsc}}","arccsc"))) + | "\\sgn" -> (tex_use_ams (); LITERAL (HTMLABLEC(FONT_UFH,"\\mathop{\\mathrm{sgn}}","sgn"))) + | "\\cot" -> LITERAL (HTMLABLEC(FONT_UFH,"\\cot ","cot")) + | "\\coth" -> LITERAL (HTMLABLEC(FONT_UFH,"\\coth ","coth")) + | "\\log" -> LITERAL (HTMLABLEC(FONT_UFH,"\\log ", "log")) + | "\\lg" -> LITERAL (HTMLABLEC(FONT_UFH,"\\lg ", "lg")) + | "\\ln" -> LITERAL (HTMLABLEC(FONT_UFH,"\\ln ", "ln")) + | "\\exp" -> LITERAL (HTMLABLEC(FONT_UFH,"\\exp ", "exp")) + | "\\min" -> LITERAL (HTMLABLEC(FONT_UFH,"\\min ", "min")) + | "\\max" -> LITERAL (HTMLABLEC(FONT_UFH,"\\max ", "max")) + | "\\gcd" -> LITERAL (HTMLABLEC(FONT_UFH,"\\gcd ", "gcd")) + | "\\deg" -> LITERAL (HTMLABLEC(FONT_UFH,"\\deg ", "deg")) + | "\\det" -> LITERAL (HTMLABLEC(FONT_UFH,"\\det ", "det")) + | "\\bullet" -> LITERAL (HTMLABLE (FONT_UFH, "\\bullet ", "•")) + | "\\bull" -> LITERAL (HTMLABLE (FONT_UFH, "\\bullet ", "•")) + | "\\angle" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UF, "\\angle ", "∠"))) + | "\\dagger" -> LITERAL (HTMLABLEM(FONT_UFH, "\\dagger ", "†")) + | "\\ddagger" -> LITERAL (HTMLABLEM(FONT_UFH, "\\ddagger ", "‡")) + | "\\Dagger" -> LITERAL (HTMLABLEM(FONT_UFH, "\\ddagger ", "‡")) + | "\\colon" -> LITERAL (HTMLABLEC(FONT_UFH, "\\colon ", ":")) + | "\\Vert" -> DELIMITER (HTMLABLEM(FONT_UFH, "\\Vert ", "||")) + | "\\vert" -> DELIMITER (HTMLABLEM(FONT_UFH, "\\vert ", "|")) + | "\\wp" -> LITERAL (HTMLABLE (FONT_UF, "\\wp ", "℘")) + | "\\weierp" -> LITERAL (HTMLABLE (FONT_UF, "\\wp ", "℘")) + | "\\wedge" -> LITERAL (HTMLABLE (FONT_UF, "\\wedge ", "∧")) + | "\\and" -> LITERAL (HTMLABLE (FONT_UF, "\\land ", "∧")) + | "\\land" -> LITERAL (HTMLABLE (FONT_UF, "\\land ", "∧")) + | "\\vee" -> LITERAL (HTMLABLE (FONT_UF, "\\vee ", "∨")) + | "\\or" -> LITERAL (HTMLABLE (FONT_UF, "\\lor ", "∨")) + | "\\lor" -> LITERAL (HTMLABLE (FONT_UF, "\\lor ", "∨")) + | "\\sub" -> LITERAL (HTMLABLE (FONT_UF, "\\subset ", "⊂")) + | "\\supe" -> LITERAL (HTMLABLE (FONT_UF, "\\supseteq ", "⊇")) + | "\\sube" -> LITERAL (HTMLABLE (FONT_UF, "\\subseteq ", "⊆")) + | "\\supset" -> LITERAL (HTMLABLE (FONT_UF, "\\supset ", "⊃")) + | "\\subset" -> LITERAL (HTMLABLE (FONT_UF, "\\subset ", "⊂")) + | "\\supseteq" -> LITERAL (HTMLABLE (FONT_UF, "\\supseteq ", "⊇")) + | "\\subseteq" -> LITERAL (HTMLABLE (FONT_UF, "\\subseteq ", "⊆")) + | "\\sqsupset" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\sqsupset ")) + | "\\sqsubset" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\sqsubset ")) + | "\\sqsupseteq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\sqsupseteq ")) + | "\\sqsubseteq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\sqsubseteq ")) + | "\\perp" -> LITERAL (HTMLABLE (FONT_UF, "\\perp ", "⊥")) + | "\\bot" -> LITERAL (HTMLABLE (FONT_UF, "\\bot ", "⊥")) + | "\\lfloor" -> DELIMITER (HTMLABLE (FONT_UF, "\\lfloor ", "⌊")) + | "\\rfloor" -> DELIMITER (HTMLABLE (FONT_UF, "\\rfloor ", "⌋")) + | "\\lceil" -> DELIMITER (HTMLABLE (FONT_UF, "\\lceil ", "⌈")) + | "\\rceil" -> DELIMITER (HTMLABLE (FONT_UF, "\\rceil ", "⌉")) + | "\\lbrace" -> DELIMITER (HTMLABLEC(FONT_UFH, "\\lbrace ", "{")) + | "\\rbrace" -> DELIMITER (HTMLABLEC(FONT_UFH, "\\rbrace ", "}")) + | "\\infty" -> LITERAL (HTMLABLEM(FONT_UF, "\\infty ", "∞")) + | "\\infin" -> LITERAL (HTMLABLEM(FONT_UF, "\\infty ", "∞")) + | "\\isin" -> LITERAL (HTMLABLE (FONT_UF, "\\in ", "∈")) + | "\\in" -> LITERAL (HTMLABLE (FONT_UF, "\\in ", "∈")) + | "\\ni" -> LITERAL (HTMLABLE (FONT_UF, "\\ni ", "∋")) + | "\\notin" -> LITERAL (HTMLABLE (FONT_UF, "\\notin ", "∉")) + | "\\smallsetminus" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\smallsetminus ")) + | "\\And" -> (tex_use_ams (); LITERAL (HTMLABLEM(FONT_UFH, "\\And ", " & "))) + | "\\forall" -> LITERAL (HTMLABLE (FONT_UFH, "\\forall ", "∀")) + | "\\exists" -> LITERAL (HTMLABLE (FONT_UFH, "\\exists ", "∃")) + | "\\exist" -> LITERAL (HTMLABLE (FONT_UFH, "\\exists ", "∃")) + | "\\equiv" -> LITERAL (HTMLABLEM(FONT_UFH, "\\equiv ", "≡")) + | "\\ne" -> LITERAL (HTMLABLEM(FONT_UFH, "\\neq ", "≠")) + | "\\neq" -> LITERAL (HTMLABLEM(FONT_UFH, "\\neq ", "≠")) + | "\\Re" -> LITERAL (HTMLABLE (FONT_UF, "\\Re ", "ℜ")) + | "\\real" -> LITERAL (HTMLABLE (FONT_UF, "\\Re ", "ℜ")) + | "\\Im" -> LITERAL (HTMLABLE (FONT_UF, "\\Im ", "ℑ")) + | "\\image" -> LITERAL (HTMLABLE (FONT_UF, "\\Im ", "ℑ")) + | "\\prime" -> LITERAL (HTMLABLE (FONT_UFH,"\\prime ", "′")) + | "\\backslash" -> DELIMITER (HTMLABLEM(FONT_UFH,"\\backslash ", "\\")) + | "\\setminus" -> LITERAL (HTMLABLEM(FONT_UFH,"\\setminus ", "\\")) + | "\\times" -> LITERAL (HTMLABLEM(FONT_UFH,"\\times ", "×")) + | "\\pm" -> LITERAL (HTMLABLEM(FONT_UFH,"\\pm ", "±")) + | "\\plusmn" -> LITERAL (HTMLABLEM(FONT_UFH,"\\pm ", "±")) + | "\\cdot" -> LITERAL (HTMLABLE (FONT_UFH,"\\cdot ", "⋅")) + | "\\AA" -> LITERAL (HTMLABLE (FONT_UFH,"\\AA ", "Å")) + | "\\cdots" -> LITERAL (HTMLABLE (FONT_UFH,"\\cdots ", "⋅⋅⋅")) + | "\\sdot" -> LITERAL (HTMLABLE (FONT_UFH,"\\cdot ", "⋅")) + | "\\oplus" -> LITERAL (HTMLABLE (FONT_UF, "\\oplus ", "⊕")) + | "\\otimes" -> LITERAL (HTMLABLE (FONT_UF, "\\otimes ", "⊗")) + | "\\cap" -> LITERAL (HTMLABLEM(FONT_UF, "\\cap ", "∩")) + | "\\cup" -> LITERAL (HTMLABLE (FONT_UF, "\\cup ", "∪")) + | "\\sqcap" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\sqcap ")) + | "\\sqcup" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\sqcup ")) + | "\\empty" -> LITERAL (HTMLABLE (FONT_UF, "\\emptyset ", "∅")) + | "\\emptyset" -> LITERAL (HTMLABLE (FONT_UF, "\\emptyset ", "∅")) + | "\\O" -> LITERAL (HTMLABLE (FONT_UF, "\\emptyset ", "∅")) + | "\\S" -> LITERAL (HTMLABLEM(FONT_UFH,"\\S ", "§")) + | "\\sect" -> LITERAL (HTMLABLEM(FONT_UFH,"\\S ", "§")) + | "\\nabla" -> LITERAL (HTMLABLE (FONT_UF, "\\nabla ", "∇")) + | "\\geq" -> LITERAL (HTMLABLE (FONT_UFH,"\\geq ", "≥")) + | "\\ge" -> LITERAL (HTMLABLE (FONT_UFH,"\\geq ", "≥")) + | "\\leq" -> LITERAL (HTMLABLE (FONT_UFH,"\\leq ", "≤")) + | "\\le" -> LITERAL (HTMLABLE (FONT_UFH,"\\leq ", "≤")) + | "\\cong" -> LITERAL (HTMLABLE (FONT_UF, "\\cong ", "≅")) + | "\\ang" -> LITERAL (HTMLABLE (FONT_UF, "\\angle ", "∠")) + | "\\part" -> LITERAL (HTMLABLEM(FONT_UF, "\\partial ", "∂")) + | "\\partial" -> LITERAL (HTMLABLEM(FONT_UF, "\\partial ", "∂")) + | "\\ldots" -> LITERAL (HTMLABLEM(FONT_UFH,"\\ldots ", "...")) + | "\\dots" -> LITERAL (HTMLABLEM(FONT_UFH,"\\dots ", "...")) + | "\\quad" -> LITERAL (HTMLABLE (FONT_UF, "\\quad "," ")) + | "\\qquad" -> LITERAL (HTMLABLE (FONT_UF, "\\qquad "," ")) + | "\\mid" -> LITERAL (HTMLABLEM(FONT_UFH,"\\mid ", " | ")) + | "\\neg" -> LITERAL (HTMLABLEM(FONT_UFH,"\\neg ", "¬")) + | "\\langle" -> DELIMITER (HTMLABLE (FONT_UFH,"\\langle ","⟨")) + | "\\rangle" -> DELIMITER (HTMLABLE (FONT_UFH,"\\rangle ","⟩")) + | "\\lang" -> DELIMITER (HTMLABLE (FONT_UFH,"\\langle ","⟨")) + | "\\rang" -> DELIMITER (HTMLABLE (FONT_UFH,"\\rangle ","⟩")) + | "\\lbrack" -> DELIMITER (HTMLABLEC(FONT_UFH,"[","[")) + | "\\rbrack" -> DELIMITER (HTMLABLEC(FONT_UFH,"]","]")) + | "\\ddots" -> LITERAL (TEX_ONLY "\\ddots ") + | "\\clubs" -> LITERAL (TEX_ONLY "\\clubsuit ") + | "\\clubsuit" -> LITERAL (TEX_ONLY "\\clubsuit ") + | "\\spades" -> LITERAL (TEX_ONLY "\\spadesuit ") + | "\\spadesuit" -> LITERAL (TEX_ONLY "\\spadesuit ") + | "\\hearts" -> LITERAL (TEX_ONLY "\\heartsuit ") + | "\\heartsuit" -> LITERAL (TEX_ONLY "\\heartsuit ") + | "\\diamonds" -> LITERAL (TEX_ONLY "\\diamondsuit ") + | "\\diamondsuit" -> LITERAL (TEX_ONLY "\\diamondsuit ") + | "\\implies" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UF, "\\implies ", "⇒"))) + | "\\mod" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mod ", "mod"))) + | "\\Diamond" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UF, "\\Diamond ", "◊"))) + | "\\dotsb" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UF, "\\dotsb ", "⋅⋅⋅"))) + | "\\reals" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{R}", "<b>R</b>"))) + | "\\Reals" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{R}", "<b>R</b>"))) + | "\\R" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{R}", "<b>R</b>"))) + | "\\cnums" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{C}", "<b>C</b>"))) + | "\\Complex" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{C}", "<b>C</b>"))) + | "\\Z" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{Z}", "<b>Z</b>"))) + | "\\natnums" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{N}", "<b>N</b>"))) + | "\\N" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{N}", "<b>N</b>"))) + | "\\lVert" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\lVert ", "||"))) + | "\\rVert" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\rVert ", "||"))) + | "\\nmid" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nmid ")) + | "\\lesssim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\lesssim ")) + | "\\ngeq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\ngeq ")) + | "\\smallsmile" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\smallsmile ")) + | "\\smallfrown" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\smallfrown ")) + | "\\nleftarrow" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nleftarrow ")) + | "\\nrightarrow" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nrightarrow ")) + | "\\trianglelefteq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\trianglelefteq ")) + | "\\trianglerighteq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\trianglerighteq ")) + | "\\square" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\square ")) + | "\\checkmark" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\checkmark ")) + | "\\supsetneq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\supsetneq ")) + | "\\subsetneq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\subsetneq ")) + | "\\Box" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Box ")) + | "\\nleq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nleq ")) + | "\\upharpoonright" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\upharpoonright ")) + | "\\upharpoonleft" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\upharpoonleft ")) + | "\\downharpoonright" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\downharpoonright ")) + | "\\downharpoonleft" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\downharpoonleft ")) + | "\\rightharpoonup" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\rightharpoonup ")) + | "\\rightharpoondown" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\rightharpoondown ")) + | "\\leftharpoonup" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\leftharpoonup ")) + | "\\leftharpoondown" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\leftharpoondown ")) + | "\\nless" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nless ")) + | "\\Vdash" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Vdash ")) + | "\\vDash" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\vDash ")) + | "\\varkappa" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\varkappa ")) + | "\\digamma" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\digamma ")) + | "\\beth" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\beth ")) + | "\\daleth" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\daleth ")) + | "\\gimel" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\gimel ")) + | "\\complement" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\complement ")) + | "\\eth" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\eth ")) + | "\\hslash" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\hslash ")) + | "\\mho" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\mho ")) + | "\\Finv" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Finv ")) + | "\\Game" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Game ")) + | "\\varlimsup" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\varlimsup ")) + | "\\varliminf" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\varliminf ")) + | "\\varinjlim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\varinjlim ")) + | "\\varprojlim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\varprojlim ")) + | "\\injlim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\injlim ")) + | "\\projlim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\projlim ")) + | "\\iint" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\iint ")) + | "\\iiint" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\iiint ")) + | "\\iiiint" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\iiiint ")) + | "\\varnothing" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\varnothing ")) + | "\\left" -> LEFT + | "\\right" -> RIGHT + | "\\hat" -> FUN_AR1 "\\hat " + | "\\widehat" -> FUN_AR1 "\\widehat " + | "\\overline" -> FUN_AR1 "\\overline " + | "\\overbrace" -> FUN_AR1 "\\overbrace " + | "\\underline" -> FUN_AR1 "\\underline " + | "\\underbrace" -> FUN_AR1 "\\underbrace " + | "\\overleftarrow" -> FUN_AR1 "\\overleftarrow " + | "\\overrightarrow" -> FUN_AR1 "\\overrightarrow " + | "\\overleftrightarrow"->FUN_AR1 "\\overleftrightarrow " + | "\\check" -> FUN_AR1 "\\check " + | "\\acute" -> FUN_AR1 "\\acute " + | "\\grave" -> FUN_AR1 "\\grave " + | "\\bar" -> FUN_AR1 "\\bar " + | "\\vec" -> FUN_AR1 "\\vec " + | "\\dot" -> FUN_AR1 "\\dot " + | "\\ddot" -> FUN_AR1 "\\ddot " + | "\\breve" -> FUN_AR1 "\\breve " + | "\\tilde" -> FUN_AR1 "\\tilde " + | "\\not" -> LITERAL (TEX_ONLY "\\not ") + | "\\choose" -> FUN_INFIX "\\choose " + | "\\atop" -> FUN_INFIX "\\atop " + | "\\binom" -> FUN_AR2 "\\binom " + | "\\frac" -> FUN_AR2h ("\\frac ", fun num den -> Html.html_render [num], "<hr style=\"{background: black}\"/>", Html.html_render [den]) + | "\\cfrac" -> (tex_use_ams (); FUN_AR2h ("\\cfrac ", fun num den -> Html.html_render [num], "<hr style=\"{background: black}\">", Html.html_render [den])) + | "\\over" -> FUN_INFIXh ("\\over ", fun num den -> Html.html_render num, "<hr style=\"{background: black}\"/>", Html.html_render den) + | "\\sqrt" -> FUN_AR1 "\\sqrt " + | "\\pmod" -> FUN_AR1hl ("\\pmod ", ("(mod ", ")")) + | "\\bmod" -> FUN_AR1hl ("\\bmod ", ("mod ", "")) + | "\\emph" -> FUN_AR1 "\\emph " + | "\\texttt" -> FUN_AR1 "\\texttt " + | "\\textbf" -> FUN_AR1 "\\textbf " + | "\\textit" -> FUN_AR1hf ("\\textit ", FONTFORCE_IT) + | "\\textrm" -> FUN_AR1hf ("\\textrm ", FONTFORCE_RM) + | "\\rm" -> DECLh ("\\rm ", FONTFORCE_RM) + | "\\it" -> DECLh ("\\it ", FONTFORCE_IT) + | "\\cal" -> DECL "\\cal " + | "\\displaystyle" -> LITERAL (TEX_ONLY "\\displaystyle ") + | "\\scriptstyle" -> LITERAL (TEX_ONLY "\\scriptstyle ") + | "\\textstyle" -> LITERAL (TEX_ONLY "\\textstyle ") + | "\\scriptscriptstyle"-> LITERAL (TEX_ONLY "\\scriptscriptstyle ") + | "\\bf" -> DECL "\\bf " + | "\\big" -> BIG "\\big " + | "\\Big" -> BIG "\\Big " + | "\\bigg" -> BIG "\\bigg " + | "\\Bigg" -> BIG "\\Bigg " + | "\\mathit" -> (tex_use_ams (); FUN_AR1hf ("\\mathit ", FONTFORCE_IT)) + | "\\mathrm" -> (tex_use_ams (); FUN_AR1hf ("\\mathrm ", FONTFORCE_RM)) + | "\\mathop" -> (tex_use_ams (); FUN_AR1 "\\mathop ") + | "\\boldsymbol" -> (tex_use_ams (); FUN_AR1 "\\boldsymbol ") + | "\\bold" -> (tex_use_ams (); FUN_AR1 "\\mathbf ") + | "\\Bbb" -> (tex_use_ams (); FUN_AR1 "\\mathbb ") + | "\\mathbf" -> (tex_use_ams (); FUN_AR1 "\\mathbf ") + | "\\mathsf" -> (tex_use_ams (); FUN_AR1 "\\mathsf ") + | "\\mathcal" -> (tex_use_ams (); FUN_AR1 "\\mathcal ") + | "\\mathbb" -> (tex_use_ams (); FUN_AR1 "\\mathbb ") + | "\\mathfrak" -> (tex_use_ams (); FUN_AR1 "\\mathfrak ") + | "\\operatorname" -> (tex_use_ams (); FUN_AR1 "\\operatorname ") + | "\\mbox" -> raise (Failure "malformatted \\mbox") + | "\\vbox" -> raise (Failure "malformatted \\vbox") + | "\\hbox" -> raise (Failure "malformatted \\hbox") + | "\\color" -> (tex_use_color (); LITERAL (TEX_ONLY "\\color")) + | s -> raise (Illegal_tex_function s) diff --git a/math/texutil.mli b/math/texutil.mli new file mode 100644 index 00000000..99d0e4ec --- /dev/null +++ b/math/texutil.mli @@ -0,0 +1,11 @@ +val render_tex : Tex.t -> string + +val set_encoding : string -> unit +val tex_use_nonascii: unit -> unit +val tex_use_ams: unit -> unit + +val get_preface : unit -> string +val get_footer : unit -> string + +exception Illegal_tex_function of string +val find: string -> Parser.token diff --git a/math/texvc.ml b/math/texvc.ml new file mode 100644 index 00000000..abddd3d0 --- /dev/null +++ b/math/texvc.ml @@ -0,0 +1,34 @@ +exception LexerException of string +let lexer_token_safe lexbuf = + try Lexer.token lexbuf + with Failure s -> raise (LexerException s) + +let render tmppath finalpath tree = + let outtex = Util.mapjoin Texutil.render_tex tree in + let md5 = Digest.to_hex (Digest.string outtex) in + begin + let mathml = Mathml.render tree + and html = Html.render tree + in print_string (match (html,!Html.conservativeness,mathml) with + None,_,None -> "+" ^ md5 + | Some h,Html.CONSERVATIVE,None -> "c" ^ md5 ^ h + | Some h,Html.MODERATE,None -> "m" ^ md5 ^ h + | Some h,Html.LIBERAL,None -> "l" ^ md5 ^ h + | Some h,Html.CONSERVATIVE,Some m -> "C" ^ md5 ^ h ^ "\000" ^ m + | Some h,Html.MODERATE,Some m -> "M" ^ md5 ^ h ^ "\000" ^ m + | Some h,Html.LIBERAL,Some m -> "L" ^ md5 ^ h ^ "\000" ^ m + | None,_,Some m -> "X" ^ md5 ^ m + ); + Render.render tmppath finalpath outtex md5 + end +let _ = + Texutil.set_encoding (try Sys.argv.(4) with _ -> "UTF-8"); + try render Sys.argv.(1) Sys.argv.(2) (Parser.tex_expr lexer_token_safe (Lexing.from_string Sys.argv.(3))) + with Parsing.Parse_error -> print_string "S" + | LexerException _ -> print_string "E" + | Texutil.Illegal_tex_function s -> print_string ("F" ^ s) + | Util.FileAlreadyExists -> print_string "-" + | Invalid_argument _ -> print_string "-" + | Failure _ -> print_string "-" + | Render.ExternalCommandFailure s -> () + | _ -> print_string "-" diff --git a/math/texvc_cgi.ml b/math/texvc_cgi.ml new file mode 100644 index 00000000..2e6079fe --- /dev/null +++ b/math/texvc_cgi.ml @@ -0,0 +1,62 @@ +open Netcgi;; +open Netcgi_types;; +open Netcgi_env;; +open Netchannels;; + +let cgi = new Netcgi.std_activation () +let out = cgi # output # output_string +let math = cgi # argument_value ~default:"" "math" +let tmppath = "/home/taw/public_html/wiki/tmp/" +let finalpath = "/home/taw/public_html/wiki/math/" +let finalurl = "http://wroclaw.taw.pl.eu.org/~taw/wiki/math/" +;; + +let h_header = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\""^ + " \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"^ + "<html><head><title>texvc</title></head><body>"^ + "<form method=post action=\"http://wroclaw.taw.pl.eu.org/~taw/cgi-bin/newcodebase/math/texvc_cgi\">"^ + "<textarea name='math' rows=10 cols=80>" +let h_middle = "</textarea><br /><input type=submit value=\"Preview\" name='preview'></form>" +let h_footer = "</body></html>\n" + +let render tmppath finalpath tree = + let outtex = Texutil.mapjoin Texutil.print tree in + let md5 = Digest.to_hex (Digest.string outtex) in + begin + out "<h3>TeX</h3>"; + out outtex; (* <, & and > should be protected *) + (try out ("<h3>HTML</h3>" ^ (Texutil.html_render tree)) + with _ -> out "<h3>HTML could not be rendered</h3>"); + try Render.render tmppath finalpath outtex md5; + out ("<h3>Image:</h3><img src=\""^finalurl^md5^".png\">") + with Util.FileAlreadyExists -> out ("<h3>Image:</h3><img src=\""^finalurl^md5^".png\">") + | Failure s -> out ("<h3>Other failure: " ^ s ^ "</h3>") + | Render.ExternalCommandFailure "latex" -> out "<h3>latex failed</h3>" + | Render.ExternalCommandFailure "dvips" -> out "<h3>dvips failed</h3>" + | _ -> out "<h3>Other failure</h3>" + end +;; + +cgi#set_header ();; + +out h_header;; +out math;; +out h_middle;; + +exception LexerException of string +let lexer_token_safe lexbuf = + try Lexer.token lexbuf + with Failure s -> raise (LexerException s) +;; +if math = "" +then () +else try + render tmppath finalpath (Parser.tex_expr lexer_token_safe (Lexing.from_string math)) + with Parsing.Parse_error -> out "<h3>Parse error</h3>" + | LexerException s -> out "<h3>Lexing failure</h3>" + | Texutil.Illegal_tex_function s -> out ("<h3>Illegal TeX function: " ^ s ^ "</h3>") + | Failure s -> out ("<h3>Other failure: " ^ s ^ "</h3>") + | _ -> out "<h3>Other failure</h3>" +;; + +out h_footer diff --git a/math/texvc_test.ml b/math/texvc_test.ml new file mode 100644 index 00000000..3bce5296 --- /dev/null +++ b/math/texvc_test.ml @@ -0,0 +1,25 @@ +exception LexerException of string +let lexer_token_safe lexbuf = + try Lexer.token lexbuf + with Failure s -> raise (LexerException s) + +let rec foo () = + try + let line = input_line stdin in + (try + let tree = Parser.tex_expr lexer_token_safe (Lexing.from_string line) in + let out = Util.mapjoin Texutil.render_tex tree in + (match Html.render tree with + Some _ -> print_string "$^\n" + | None -> print_string "$_\n"; + ) + with + Texutil.Illegal_tex_function s -> print_string ("$T" ^ s ^ " " ^ line ^ "\n") + | LexerException s -> print_string ("$L" ^ line ^ "\n") + | _ -> print_string ("$ " ^ line ^ "\n")); + flush stdout; + foo (); + with + End_of_file -> () +;; +foo ();; diff --git a/math/texvc_tex.ml b/math/texvc_tex.ml new file mode 100644 index 00000000..30c0f671 --- /dev/null +++ b/math/texvc_tex.ml @@ -0,0 +1,3 @@ +Texutil.set_encoding (try Sys.argv.(2) with _ -> "UTF-8"); +try print_string (Util.mapjoin Texutil.render_tex (Parser.tex_expr Lexer.token (Lexing.from_string Sys.argv.(1)))) +with _ -> () diff --git a/math/util.ml b/math/util.ml new file mode 100644 index 00000000..f0458562 --- /dev/null +++ b/math/util.ml @@ -0,0 +1,17 @@ +let mapjoin f l = (List.fold_left (fun a b -> a ^ (f b)) "" l) +let mapjoine e f = function + [] -> "" + | h::t -> (List.fold_left (fun a b -> a ^ e ^ (f b)) (f h) t) + +exception FileAlreadyExists +let open_out_unless_exists path = + if Sys.file_exists path + then raise FileAlreadyExists + else open_out path + +let run_in_other_directory tmppath cmd = + let prevdir = Sys.getcwd () in( + Sys.chdir tmppath; + let retval = Sys.command cmd in + (Sys.chdir prevdir; retval) + ) |