Initial stab at breaking math/texvc out to Math extension.

* (bug 14202) $wgUseTeX has been superseded by the Math extension. To re-enable
  math conversion after upgrading, obtain the Math extension from SVN or from
  http://www.mediawiki.org/wiki/Extension:Math and add to LocalSettings.php:
  require_once "$IP/extensions/Math/Math.php";

This is an initial stab, and a few things remain to be cleaned up:
* messages need to be moved from core to extension
* MW_MATH_* constants should be moved to the extension from core
* old back-compat math names interfaces using those constants should be removed from message files
* classic edit toolbar's math button should be added from the extension (or else dropped) -- currently there's not a clean hook, but could do it by JS
* couple of things like the 'armourMath' function on Language & LanguageConverter may want to be redone just as an unconditional, if that's simpler.

Setting $wgUseTeX alone will no longer have any affect. The var's still there for the moment as a few bits still need to be fully moved out from core.
This commit is contained in:
Brion Vibber 2011-04-09 00:39:40 +00:00
commit c4d9349786
24 changed files with 2146 additions and 0 deletions

348
Math.body.php Normal file
View File

@ -0,0 +1,348 @@
<?php
/**
* MediaWiki math extension
*
* (c) 2002-2011 Tomasz Wegrzanowski, Brion Vibber, and other MediaWiki contributors
* GPLv2 license; info in main package.
*
* Contain everything related to <math> </math> parsing
* @file
* @ingroup Parser
*/
/**
* Takes LaTeX fragments, sends them to a helper program (texvc) for rendering
* to rasterized PNG and HTML and MathML approximations. An appropriate
* rendering form is picked and returned.
*
* @author Tomasz Wegrzanowski, with additions by Brion Vibber (2003, 2004)
* @ingroup Parser
*/
class MathRenderer {
var $mode = MW_MATH_MODERN;
var $tex = '';
var $inputhash = '';
var $hash = '';
var $html = '';
var $mathml = '';
var $conservativeness = 0;
function __construct( $tex, $params=array() ) {
$this->tex = $tex;
$this->params = $params;
}
function setOutputMode( $mode ) {
$this->mode = $mode;
}
function render() {
global $wgTmpDirectory, $wgInputEncoding;
global $wgTexvc, $wgMathCheckFiles, $wgTexvcBackgroundColor;
if( $this->mode == MW_MATH_SOURCE ) {
# No need to render or parse anything more!
# New lines are replaced with spaces, which avoids confusing our parser (bugs 23190, 22818)
return ('<span class="tex" dir="ltr">$ ' . str_replace( "\n", " ", htmlspecialchars( $this->tex ) ) . ' $</span>');
}
if( $this->tex == '' ) {
return; # bug 8372
}
if( !$this->_recall() ) {
if( $wgMathCheckFiles ) {
# Ensure that the temp and output directories are available before continuing...
if( !file_exists( $wgTmpDirectory ) ) {
if( !wfMkdirParents( $wgTmpDirectory ) ) {
return $this->_error( 'math_bad_tmpdir' );
}
} elseif( !is_dir( $wgTmpDirectory ) || !is_writable( $wgTmpDirectory ) ) {
return $this->_error( 'math_bad_tmpdir' );
}
}
if( !is_executable( $wgTexvc ) ) {
return $this->_error( 'math_notexvc' );
}
$cmd = $wgTexvc . ' ' .
escapeshellarg( $wgTmpDirectory ).' '.
escapeshellarg( $wgTmpDirectory ).' '.
escapeshellarg( $this->tex ).' '.
escapeshellarg( $wgInputEncoding ).' '.
escapeshellarg( $wgTexvcBackgroundColor );
if ( wfIsWindows() ) {
# Invoke it within cygwin sh, because texvc expects sh features in its default shell
$cmd = 'sh -c ' . wfEscapeShellArg( $cmd );
}
wfDebug( "TeX: $cmd\n" );
$contents = wfShellExec( $cmd );
wfDebug( "TeX output:\n $contents\n---\n" );
if (strlen($contents) == 0) {
return $this->_error( 'math_unknown_error' );
}
$retval = substr ($contents, 0, 1);
$errmsg = '';
if (($retval == 'C') || ($retval == 'M') || ($retval == 'L')) {
if ($retval == 'C') {
$this->conservativeness = 2;
} else if ($retval == 'M') {
$this->conservativeness = 1;
} else {
$this->conservativeness = 0;
}
$outdata = substr ($contents, 33);
$i = strpos($outdata, "\000");
$this->html = substr($outdata, 0, $i);
$this->mathml = substr($outdata, $i+1);
} else if (($retval == 'c') || ($retval == 'm') || ($retval == 'l')) {
$this->html = substr ($contents, 33);
if ($retval == 'c') {
$this->conservativeness = 2;
} else if ($retval == 'm') {
$this->conservativeness = 1;
} else {
$this->conservativeness = 0;
}
$this->mathml = null;
} else if ($retval == 'X') {
$this->html = null;
$this->mathml = substr ($contents, 33);
$this->conservativeness = 0;
} else if ($retval == '+') {
$this->html = null;
$this->mathml = null;
$this->conservativeness = 0;
} else {
$errbit = htmlspecialchars( substr($contents, 1) );
switch( $retval ) {
case 'E':
$errmsg = $this->_error( 'math_lexing_error', $errbit );
break;
case 'S':
$errmsg = $this->_error( 'math_syntax_error', $errbit );
break;
case 'F':
$errmsg = $this->_error( 'math_unknown_function', $errbit );
break;
default:
$errmsg = $this->_error( 'math_unknown_error', $errbit );
}
}
if ( !$errmsg ) {
$this->hash = substr ($contents, 1, 32);
}
wfRunHooks( 'MathAfterTexvc', array( &$this, &$errmsg ) );
if ( $errmsg ) {
return $errmsg;
}
if (!preg_match("/^[a-f0-9]{32}$/", $this->hash)) {
return $this->_error( 'math_unknown_error' );
}
if( !file_exists( "$wgTmpDirectory/{$this->hash}.png" ) ) {
return $this->_error( 'math_image_error' );
}
if( filesize( "$wgTmpDirectory/{$this->hash}.png" ) == 0 ) {
return $this->_error( 'math_image_error' );
}
$hashpath = $this->_getHashPath();
if( !file_exists( $hashpath ) ) {
wfSuppressWarnings();
$ret = wfMkdirParents( $hashpath, 0755 );
wfRestoreWarnings();
if( !$ret ) {
return $this->_error( 'math_bad_output' );
}
} elseif( !is_dir( $hashpath ) || !is_writable( $hashpath ) ) {
return $this->_error( 'math_bad_output' );
}
if( !rename( "$wgTmpDirectory/{$this->hash}.png", "$hashpath/{$this->hash}.png" ) ) {
return $this->_error( 'math_output_error' );
}
# Now save it back to the DB:
if ( !wfReadOnly() ) {
$outmd5_sql = pack('H32', $this->hash);
$md5_sql = pack('H32', $this->md5); # Binary packed, not hex
$dbw = wfGetDB( DB_MASTER );
$dbw->replace( 'math', array( 'math_inputhash' ),
array(
'math_inputhash' => $dbw->encodeBlob($md5_sql),
'math_outputhash' => $dbw->encodeBlob($outmd5_sql),
'math_html_conservativeness' => $this->conservativeness,
'math_html' => $this->html,
'math_mathml' => $this->mathml,
), __METHOD__
);
}
// If we're replacing an older version of the image, make sure it's current.
global $wgUseSquid;
if ( $wgUseSquid ) {
$urls = array( $this->_mathImageUrl() );
$u = new SquidUpdate( $urls );
$u->doUpdate();
}
}
return $this->_doRender();
}
function _error( $msg, $append = '' ) {
$mf = htmlspecialchars( wfMsg( 'math_failure' ) );
$errmsg = htmlspecialchars( wfMsg( $msg ) );
$source = htmlspecialchars( str_replace( "\n", ' ', $this->tex ) );
return "<strong class='error'>$mf ($errmsg$append): $source</strong>\n";
}
function _recall() {
global $wgMathDirectory, $wgMathCheckFiles;
$this->md5 = md5( $this->tex );
$dbr = wfGetDB( DB_SLAVE );
$rpage = $dbr->selectRow( 'math',
array( 'math_outputhash','math_html_conservativeness','math_html','math_mathml' ),
array( 'math_inputhash' => $dbr->encodeBlob(pack("H32", $this->md5))), # Binary packed, not hex
__METHOD__
);
if( $rpage !== false ) {
# Tailing 0x20s can get dropped by the database, add it back on if necessary:
$xhash = unpack( 'H32md5', $dbr->decodeBlob($rpage->math_outputhash) . " " );
$this->hash = $xhash ['md5'];
$this->conservativeness = $rpage->math_html_conservativeness;
$this->html = $rpage->math_html;
$this->mathml = $rpage->math_mathml;
$filename = $this->_getHashPath() . "/{$this->hash}.png";
if( !$wgMathCheckFiles ) {
// Short-circuit the file existence & migration checks
return true;
}
if( file_exists( $filename ) ) {
if( filesize( $filename ) == 0 ) {
// Some horrible error corrupted stuff :(
wfSuppressWarnings();
unlink( $filename );
wfRestoreWarnings();
} else {
return true;
}
}
if( file_exists( $wgMathDirectory . "/{$this->hash}.png" ) ) {
$hashpath = $this->_getHashPath();
if( !file_exists( $hashpath ) ) {
wfSuppressWarnings();
$ret = wfMkdirParents( $hashpath, 0755 );
wfRestoreWarnings();
if( !$ret ) {
return false;
}
} elseif( !is_dir( $hashpath ) || !is_writable( $hashpath ) ) {
return false;
}
if ( function_exists( "link" ) ) {
return link ( $wgMathDirectory . "/{$this->hash}.png",
$hashpath . "/{$this->hash}.png" );
} else {
return rename ( $wgMathDirectory . "/{$this->hash}.png",
$hashpath . "/{$this->hash}.png" );
}
}
}
# Missing from the database and/or the render cache
return false;
}
/**
* Select among PNG, HTML, or MathML output depending on
*/
function _doRender() {
if( $this->mode == MW_MATH_MATHML && $this->mathml != '' ) {
return Xml::tags( 'math',
$this->_attribs( 'math',
array( 'xmlns' => 'http://www.w3.org/1998/Math/MathML' ) ),
$this->mathml );
}
if (($this->mode == MW_MATH_PNG) || ($this->html == '') ||
(($this->mode == MW_MATH_SIMPLE) && ($this->conservativeness != 2)) ||
(($this->mode == MW_MATH_MODERN || $this->mode == MW_MATH_MATHML) && ($this->conservativeness == 0))) {
return $this->_linkToMathImage();
} else {
return Xml::tags( 'span',
$this->_attribs( 'span',
array( 'class' => 'texhtml',
'dir' => 'ltr'
) ),
$this->html );
}
}
function _attribs( $tag, $defaults=array(), $overrides=array() ) {
$attribs = Sanitizer::validateTagAttributes( $this->params, $tag );
$attribs = Sanitizer::mergeAttributes( $defaults, $attribs );
$attribs = Sanitizer::mergeAttributes( $attribs, $overrides );
return $attribs;
}
function _linkToMathImage() {
$url = $this->_mathImageUrl();
return Xml::element( 'img',
$this->_attribs(
'img',
array(
'class' => 'tex',
'alt' => $this->tex ),
array(
'src' => $url ) ) );
}
function _mathImageUrl() {
global $wgMathPath;
$dir = $this->_getHashSubPath();
return "$wgMathPath/$dir/{$this->hash}.png";
}
function _getHashPath() {
global $wgMathDirectory;
$path = $wgMathDirectory .'/' . $this->_getHashSubPath();
wfDebug( "TeX: getHashPath, hash is: $this->hash, path is: $path\n" );
return $path;
}
function _getHashSubPath() {
return substr($this->hash, 0, 1)
.'/'. substr($this->hash, 1, 1)
.'/'. substr($this->hash, 2, 1);
}
public static function renderMath( $tex, $params=array(), ParserOptions $parserOptions = null ) {
$math = new MathRenderer( $tex, $params );
if ( $parserOptions )
$math->setOutputMode( $parserOptions->getMath() );
return $math->render();
}
}

44
Math.hooks.php Normal file
View File

@ -0,0 +1,44 @@
<?php
/**
* MediaWiki math extension
*
* (c) 2002-2011 various MediaWiki contributors
* GPLv2 license; info in main package.
*/
class MathHooks {
static function setup() {
global $wgMathPath, $wgMathDirectory;
global $wgUploadPath, $wgUploadDirectory;
if ( $wgMathPath === false ) $wgMathPath = "{$wgUploadPath}/math";
if ( $wgMathDirectory === false ) $wgMathDirectory = "{$wgUploadDirectory}/math";
}
static function onParserFirstCallInit($parser)
{
$parser->setHook( 'math', array( 'MathHooks', 'mathTagHook' ) );
return true;
}
/**
* @param $content
* @param $attributes
* @param $parser Parser
* @return
*/
static function mathTagHook( $content, $attributes, $parser ) {
global $wgContLang;
return $wgContLang->armourMath( MathRenderer::renderMath( $content, $attributes, $parser->getOptions() ) );
}
static function onGetPreferences( $user, &$defaultPreferences ) {
global $wgLang;
$defaultPreferences['math'] = array(
'type' => 'radio',
'options' => array_flip( array_map( 'wfMsgHtml', $wgLang->getMathNames() ) ),
'label' => '&#160;',
'section' => 'rendering/math',
);
return true;
}
}

64
Math.php Normal file
View File

@ -0,0 +1,64 @@
<?php
/**
* MediaWiki math extension
*
* (c) 2002-2011 various MediaWiki contributors
* GPLv2 license; info in main package.
*/
/** For back-compat */
$wgUseTeX = true;
/** Location of the texvc binary */
$wgTexvc = dirname( __FILE__ ) . '/math/texvc';
/**
* Texvc background color
* use LaTeX color format as used in \special function
* for transparent background use value 'Transparent' for alpha transparency or
* 'transparent' for binary transparency.
*/
$wgTexvcBackgroundColor = 'transparent';
/**
* Normally when generating math images, we double-check that the
* directories we want to write to exist, and that files that have
* been generated still exist when we need to bring them up again.
*
* This lets us give useful error messages in case of permission
* problems, and automatically rebuild images that have been lost.
*
* On a big site with heavy NFS traffic this can be slow and flaky,
* so sometimes we want to short-circuit it by setting this to false.
*/
$wgMathCheckFiles = true;
/**
* The URL path of the math directory. Defaults to "{$wgUploadPath}/math".
*
* See http://www.mediawiki.org/wiki/Manual:Enable_TeX for details about how to
* set up mathematical formula display.
*/
$wgMathPath = false;
/**
* The filesystem path of the math directory.
* Defaults to "{$wgUploadDirectory}/math".
*
* See http://www.mediawiki.org/wiki/Manual:Enable_TeX for details about how to
* set up mathematical formula display.
*/
$wgMathDirectory = false;
////////// end of config settings.
$wgExtensionFunctions[] = 'MathHooks::setup';
$wgHooks['ParserFirstCallInit'][] = 'MathHooks::onParserFirstCallInit';
$wgHooks['GetPreferences'][] = 'MathHooks::onGetPreferences';
$wgAutoloadClasses['MathHooks'] = dirname( __FILE__ ) . '/Math.hooks.php';
$wgAutoloadClasses['MathRenderer'] = dirname( __FILE__ ) . '/Math.body.php';
$wgParserTestFiles[] = dirname( __FILE__ ) . "/mathParserTests.txt";

1
math/.htaccess Normal file
View File

@ -0,0 +1 @@
Deny from all

87
math/Makefile Normal file
View File

@ -0,0 +1,87 @@
.PHONY: clean all
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
COMMON_NATIVE_OBJ =util.cmx parser.cmx html.cmx mathml.cmx texutil.cmx lexer.cmx
COMMON_BYTECODE_OBJ=util.cmo parser.cmo html.cmo mathml.cmo texutil.cmo lexer.cmo
all: texvc texvc_test texvc_tex
cgi: texvc_cgi.cmo texvc_cgi
clean:
rm -f $(OBJ)
# Native versions
texvc: $(COMMON_NATIVE_OBJ) render.cmx texvc.cmx
ocamlopt -o $@ unix.cmxa $^
texvc_test: $(COMMON_NATIVE_OBJ) lexer.cmx texvc_test.cmx
ocamlopt -o $@ $^
texvc_tex: $(COMMON_NATIVE_OBJ) texvc_tex.cmx
ocamlopt -o $@ $^
# Bytecode version
texvc.bc: $(COMMON_BYTECODE_OBJ) render.cmo texvc.cmo
ocamlc -o $@ unix.cma $^
# CGI related targets:
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 $@
#
# Pattern rules
#
# .ml source .mli interface
# .cmi compiled interface
# .cmo object .cma library object
# .cmx object file .cmxa library object file
%.ml: %.mll
ocamllex $<
%.mli %.ml: %.mly
ocamlyacc $<
%.cmo: %.ml
ocamlc -c $<
%.cmx: %.ml
ocamlopt -c $<
%.cmi: %.mli
ocamlc -c $<
# Various dependencies
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

119
math/README Normal file
View File

@ -0,0 +1,119 @@
== About texvc ==
texvc takes LaTeX-compatible equations and produces formatted output in HTML,
MathML, and (via LaTeX/dvipng) 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://www.mediawiki.org) and is
under the GPL license.
Please report bugs at: https://bugzilla.wikimedia.org/
with "MediaWiki extensions" as product and "texvc" as component.
== 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, dvipng. These need to be installed and in
the PATH: latex, dvipng
AMS* packages for LaTeX also need to be installed. Without AMS* some equations
will render correctly while others won't render. Most distributions of TeX
already contain AMS*. In Debian/Ubuntu you need to install tetex-extra.
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.
Then you'll need to set $wgUseTeX to true in your LocalSettings.php. By default,
MediaWiki will search in this directory for texvc, if you moved it elsewhere,
you'll have to modify $wgTexvc and set it to the path of the texvc executable.
== 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> <color>
Be sure to properly quote the TeX code!
Example:
texvc /home/wiki/tmp /home/wiki/math "y=x+2" iso-8859-1 "rgb 1.0 1.0 1.0"
=== 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 ==
Unfortunately, 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.
If some equations render correctly while others don't, you probably don't have
AMS* packages for LaTeX installed. Most distributions of TeX come with AMS*.
In Debian/Ubuntu AMS* is in tetex-extra package.
To check if that is the problem you can try those two equations:
x + y
x \implies y
The first uses only standard LaTeX, while the second uses symbol \implies from AMS*.
If the first renders, but the second doesn't, you need to install AMS*.
== Hacking ==
Before you start hacking on the math package its good to know the workflow,
which is basically:
1. texvc gets called by Math/Math.body.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. dvipng(1) gets called to create a .png file
See render.ml for this process (commenting out the removal of
the temporary file is useful for debugging).

3
math/TODO Normal file
View File

@ -0,0 +1,3 @@
* It would be better if PNGs were transparent
* CJK support
* Documentation, in particular about instalation of Latex support for Unicode

142
math/html.ml Normal file
View File

@ -0,0 +1,142 @@
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_DQN (a)::r -> (html_liberal ();
let bs = html_render_flat ctx [a] in "<sub>"^bs^"</sub>")^html_render_flat ctx r
| TEX_UQN (a)::r -> (html_liberal ();
let bs = html_render_flat ctx [a] in "<sup>"^bs^"</sup>")^html_render_flat ctx r
| TEX_FQN (a,b)::r -> (html_liberal ();
(let bs = html_render_flat ctx [a] in let cs = html_render_flat ctx [b] in "<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_FUN2nb _::_ -> 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 -> "","<span style='font-size: x-large; font-family: serif;'>"^s^"</span>",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,"<span style='font-size: x-large; font-family: serif;'>"^s^"</span>",""
| 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,"<span style='font-size: x-large; font-family: serif;'>"^s^"</span>",bs)
| false, s -> ("",(s^"<sub>"^bs^"</sub><sup>"^cs^"</sup>"),""))::html_render_deep ctx r)
| TEX_DQN (a)::r -> (let bs = html_render_flat ctx [a] in "",("<sub>"^bs^"</sub>"),"")::html_render_deep ctx r
| TEX_UQN (a)::r -> (let bs = html_render_flat ctx [a] in "",("<sup>"^bs^"</sup>"),"")::html_render_deep ctx r
| TEX_FQN (a,b)::r -> (html_liberal ();
(let bs = html_render_flat ctx [a] in let cs = html_render_flat ctx [b] in
("",("<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_FUN2nb _::_ -> 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
"\n<table>\n" ^
"\t\t<tr style='text-align: center; vertical-align: bottom;'>" ^ ustr ^ "</tr>\n" ^
"\t\t<tr style='text-align: center;'>" ^ mstr ^ "</tr>\n" ^
"</table>\n"
| 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
"\n<table>\n" ^
"\t\t<tr style='text-align: center;'>" ^ mstr ^ "</tr>\n" ^
"\t\t<tr style='text-align: center; vertical-align: top;'>" ^ dstr ^ "</tr>\n" ^
"</table>\n"
| 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
"\n<table>\n" ^
"\t\t<tr style='text-align: center; vertical-align: bottom;'>" ^ ustr ^ "</tr>\n" ^
"\t\t<tr style='text-align: center;'>" ^ mstr ^ "</tr>\n" ^
"\t\t<tr style='text-align: center; vertical-align: top;'>" ^ dstr ^ "</tr>\n" ^
"</table>\n"
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

5
math/html.mli Normal file
View File

@ -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

108
math/lexer.mll Normal file
View File

@ -0,0 +1,108 @@
{
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 }
| "\\text" space * '{' boxchars + '}'
{ Texutil.tex_use_ams (); let str = Lexing.lexeme lexbuf in
let n = String.index str '{' + 1 in
BOX ("\\text", String.sub str n (String.length str - n - 1)) }
| "\\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,"-"," &minus; ",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" }
| "\\xleftarrow" space * "[" { Texutil.tex_use_ams(); FUN_AR1opt "\\xleftarrow" }
| "\\xrightarrow" space * "[" { Texutil.tex_use_ams(); FUN_AR1opt "\\xrightarrow" }
| "\\," { LITERAL (HTMLABLE (FONT_UF, "\\,","&nbsp;")) }
| "\\ " { LITERAL (HTMLABLE (FONT_UF, "\\ ","&nbsp;")) }
| "\\;" { LITERAL (HTMLABLE (FONT_UF, "\\;","&nbsp;")) }
| "\\!" { 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,"\\$","$")) }
| "\\&" { LITERAL (HTMLABLEC (FONT_RM,"\\&","&amp;")) }
| "&" { 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{array}" { Texutil.tex_use_ams(); BEGIN_ARRAY }
| "\\end{array}" { END_ARRAY }
| "\\begin{align}" { Texutil.tex_use_ams(); BEGIN_ALIGN }
| "\\end{align}" { END_ALIGN }
| "\\begin{alignat}" { Texutil.tex_use_ams(); BEGIN_ALIGNAT }
| "\\end{alignat}" { END_ALIGNAT }
| "\\begin{smallmatrix}" { Texutil.tex_use_ams(); BEGIN_SMALLMATRIX }
| "\\end{smallmatrix}" { END_SMALLMATRIX }
| "\\begin{cases}" { Texutil.tex_use_ams(); BEGIN_CASES }
| "\\end{cases}" { END_CASES }
| '>' { LITERAL (HTMLABLEC(FONT_UFH,">"," &gt; ")) }
| '<' { LITERAL (HTMLABLEC(FONT_UFH,"<"," &lt; ")) }
| '%' { LITERAL (HTMLABLEC(FONT_UFH,"\\%","%")) }
| '$' { LITERAL (HTMLABLEC(FONT_UFH,"\\$","$")) }
| '~' { LITERAL (HTMLABLE (FONT_UF, "~","&nbsp;")) }
| '[' { DELIMITER (HTMLABLEC(FONT_UFH,"[","[")) }
| ']' { SQ_CLOSE }
| '{' { CURLY_OPEN }
| '}' { CURLY_CLOSE }
| '^' { SUP }
| '_' { SUB }
| eof { EOF }

20
math/mathml.ml Normal file
View File

@ -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

1
math/mathml.mli Normal file
View File

@ -0,0 +1 @@
val render : Tex.t list -> string option

118
math/parser.mly Normal file
View File

@ -0,0 +1,118 @@
%{
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 FUN_AR2nb
%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 BEGIN_ARRAY BEGIN_ALIGN BEGIN_ALIGNAT BEGIN_SMALLMATRIX
%token END__MATRIX END_PMATRIX END_BMATRIX END_BBMATRIX END_VMATRIX END_VVMATRIX END_CASES END_ARRAY END_ALIGN END_ALIGNAT END_SMALLMATRIX
%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_dqn { TEX_DQN($1) }
| lit_uqn { TEX_UQN($1) }
| 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_dqn SUP lit { TEX_FQN($1, $3) }
lit_uq:
lit SUP lit { $1,$3 }
lit_dq:
lit SUB lit { $1,$3 }
lit_uqn:
SUP lit { $2 }
lit_dqn:
SUB lit { $2 }
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_AR2nb lit lit { TEX_FUN2nb($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_ARRAY matrix END_ARRAY { TEX_MATRIX ("array", $2) }
| BEGIN_ALIGN matrix END_ALIGN { TEX_MATRIX ("aligned", $2) }
| BEGIN_ALIGNAT matrix END_ALIGNAT { TEX_MATRIX ("alignedat", $2) }
| BEGIN_SMALLMATRIX matrix END_SMALLMATRIX { TEX_MATRIX ("smallmatrix", $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 }
;;

58
math/render.ml Normal file
View File

@ -0,0 +1,58 @@
(* vim: set sw=8 ts=8 et: *)
let cmd_dvips tmpprefix = "dvips -q -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"
(* Putting -bg Transparent in dvipng's arguments will give full-alpha transparency *)
(* Note that IE have problems with such PNGs and need an additional javascript snippet *)
(* Putting -bg transparent in dvipng's arguments will give binary transparency *)
let cmd_dvipng tmpprefix finalpath backcolor = "dvipng -bg \'" ^ backcolor ^ "\' -gamma 1.5 -D 120 -T tight --strict " ^ tmpprefix ^ ".dvi -o " ^ finalpath ^ " >/dev/null 2>/dev/null"
exception ExternalCommandFailure of string
let render tmppath finalpath outtex md5 backcolor =
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");
if Sys.file_exists (tmpprefix ^ ".ps")
then Sys.remove (tmpprefix ^ ".ps");
end in
let f = (Util.open_out_unless_exists (tmpprefix ^ ".tex")) in
begin
(* Assemble final output in file 'f' *)
output_string f (Texutil.get_preface ());
output_string f outtex;
output_string f (Texutil.get_footer ());
close_out f;
(* TODO: document *)
if Util.run_in_other_directory tmppath (cmd_latex tmpprefix0) != 0
then (
unlink_all (); raise (ExternalCommandFailure "latex")
) else if (Sys.command (cmd_dvipng tmpprefix (finalpath^"/"^md5^".png") backcolor) != 0)
then (
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 ()
)
) else (
unlink_all ()
)
end

20
math/render_info.mli Normal file
View File

@ -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

23
math/tex.mli Normal file
View File

@ -0,0 +1,23 @@
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_FQN of t * t
| TEX_DQN of t
| TEX_UQN of 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_FUN2nb 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

760
math/texutil.ml Normal file
View File

@ -0,0 +1,760 @@
(* vim: set sw=8 ts=8 et: *)
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_FQN (a,b) -> "_{" ^ (render_tex a) ^ "}^{" ^ (render_tex b) ^ "}"
| TEX_DQN (a) -> "_{" ^ (render_tex a) ^ "}"
| TEX_UQN (a) -> "^{" ^ (render_tex a) ^ "}"
| 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_FUN2nb (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
(* module properties *)
let modules_ams = ref false
let modules_nonascii = ref false
let modules_encoding = ref UTF8
let modules_color = ref false
(* wrappers to easily set / reset module properties *)
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
)
(* Return TeX fragment for one of the encodings in (UTF8,LATIN1,LATIN2) *)
let get_encoding = function
UTF8 -> "\\usepackage{ucs}\n\\usepackage[utf8]{inputenc}\n"
| LATIN1 -> "\\usepackage[latin1]{inputenc}\n"
| LATIN2 -> "\\usepackage[latin2]{inputenc}\n"
(* TeX fragment inserted before the output *)
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 "") ^
"\\usepackage{cancel}\n\\pagestyle{empty}\n\\begin{document}\n$$\n"
(* TeX fragment appended after the content *)
let get_footer () = "\n$$\n\\end{document}\n"
(* Default to UTF8 *)
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;"))
| "\\Alpha" -> (tex_use_ams (); LITERAL (HTMLABLEC (FONT_UF,
"\\mathrm{A}", "&Alpha;")))
| "\\beta" -> LITERAL (HTMLABLEC (FONT_UF, "\\beta ", "&beta;"))
| "\\Beta" -> (tex_use_ams (); LITERAL (HTMLABLEC (FONT_UF,
"\\mathrm{B}", "&Beta;")))
| "\\gamma" -> LITERAL (HTMLABLEC (FONT_UF, "\\gamma ", "&gamma;"))
| "\\Gamma" -> LITERAL (HTMLABLEC (FONT_UF, "\\Gamma ", "&Gamma;"))
| "\\delta" -> LITERAL (HTMLABLEC (FONT_UF, "\\delta ", "&delta;"))
| "\\Delta" -> LITERAL (HTMLABLEC (FONT_UF, "\\Delta ", "&Delta;"))
| "\\epsilon" -> LITERAL (TEX_ONLY "\\epsilon ")
| "\\Epsilon" -> (tex_use_ams (); LITERAL (HTMLABLEC (FONT_UF,
"\\mathrm{E}", "&Epsilon;")))
| "\\varepsilon" -> LITERAL (TEX_ONLY "\\varepsilon ")
| "\\zeta" -> LITERAL (HTMLABLEC (FONT_UF, "\\zeta ", "&zeta;"))
| "\\Zeta" -> (tex_use_ams (); LITERAL (HTMLABLEC (FONT_UF,
"\\mathrm{Z}", "&Zeta;")))
| "\\eta" -> LITERAL (HTMLABLEC (FONT_UF, "\\eta ", "&eta;"))
| "\\Eta" -> (tex_use_ams (); LITERAL (HTMLABLEC (FONT_UF,
"\\mathrm{H}", "&Eta;")))
| "\\theta" -> LITERAL (HTMLABLEC (FONT_UF, "\\theta ", "&theta;"))
| "\\Theta" -> LITERAL (HTMLABLEC (FONT_UF, "\\Theta ", "&Theta;"))
| "\\vartheta" -> LITERAL (HTMLABLE (FONT_UF, "\\vartheta ", "&thetasym;"))
| "\\thetasym" -> LITERAL (HTMLABLE (FONT_UF, "\\vartheta ", "&thetasym;"))
| "\\iota" -> LITERAL (HTMLABLEC (FONT_UF, "\\iota ", "&iota;"))
| "\\Iota" -> (tex_use_ams (); LITERAL (HTMLABLEC (FONT_UF,
"\\mathrm{I}", "&Iota;")))
| "\\kappa" -> LITERAL (HTMLABLEC (FONT_UF, "\\kappa ", "&kappa;"))
| "\\Kappa" -> (tex_use_ams (); LITERAL (HTMLABLEC (FONT_UF,
"\\mathrm{K}", "&Kappa;")))
| "\\lambda" -> LITERAL (HTMLABLEC (FONT_UF, "\\lambda ", "&lambda;"))
| "\\Lambda" -> LITERAL (HTMLABLEC (FONT_UF, "\\Lambda ", "&Lambda;"))
| "\\mu" -> LITERAL (HTMLABLEC (FONT_UF, "\\mu ", "&mu;"))
| "\\Mu" -> (tex_use_ams (); LITERAL (HTMLABLEC (FONT_UF,
"\\mathrm{M}", "&Mu;")))
| "\\nu" -> LITERAL (HTMLABLEC (FONT_UF, "\\nu ", "&nu;"))
| "\\Nu" -> (tex_use_ams (); LITERAL (HTMLABLEC (FONT_UF,
"\\mathrm{N}", "&Nu;")))
| "\\omicron" -> (tex_use_ams (); LITERAL (HTMLABLEC (FONT_UF,
"\\mathrm{o}", "&omicron;")))
| "\\Omicron" -> (tex_use_ams (); LITERAL (HTMLABLEC (FONT_UF,
"\\mathrm{O}", "&Omicron;")))
| "\\pi" -> LITERAL (HTMLABLEC (FONT_UF, "\\pi ", "&pi;"))
| "\\Pi" -> LITERAL (HTMLABLEC (FONT_UF, "\\Pi ", "&Pi;"))
| "\\varpi" -> LITERAL (TEX_ONLY "\\varpi ")
| "\\rho" -> LITERAL (HTMLABLEC (FONT_UF, "\\rho ", "&rho;"))
| "\\Rho" -> (tex_use_ams (); LITERAL (HTMLABLEC (FONT_UF,
"\\mathrm{P}", "&Rho;")))
| "\\varrho" -> LITERAL (TEX_ONLY "\\varrho ")
| "\\sim" -> LITERAL (HTMLABLEC (FONT_UF, "\\sim ", "&sim;"))
| "\\sigma" -> LITERAL (HTMLABLEC (FONT_UF, "\\sigma ", "&sigma;"))
| "\\Sigma" -> LITERAL (HTMLABLEC (FONT_UF, "\\Sigma ", "&Sigma;"))
| "\\varsigma" -> LITERAL (TEX_ONLY "\\varsigma ")
| "\\tau" -> LITERAL (HTMLABLEC (FONT_UF, "\\tau ", "&tau;"))
| "\\Tau" -> (tex_use_ams (); LITERAL (HTMLABLEC (FONT_UF,
"\\mathrm{T}", "&Tau;")))
| "\\upsilon" -> LITERAL (HTMLABLEC (FONT_UF, "\\upsilon ", "&upsilon;"))
| "\\Upsilon" -> LITERAL (HTMLABLEC (FONT_UF, "\\Upsilon ", "&Upsilon;"))
| "\\phi" -> LITERAL (TEX_ONLY "\\phi ")
| "\\Phi" -> LITERAL (HTMLABLEC (FONT_UF, "\\Phi ", "&Phi;"))
| "\\varphi" -> LITERAL (TEX_ONLY "\\varphi ")
| "\\chi" -> LITERAL (HTMLABLEC (FONT_UF, "\\chi ", "&chi;"))
| "\\Chi" -> (tex_use_ams (); LITERAL (HTMLABLEC (FONT_UF,
"\\mathrm{X}", "&Chi;")))
| "\\psi" -> LITERAL (HTMLABLEC (FONT_UF, "\\psi ", "&psi;"))
| "\\Psi" -> LITERAL (HTMLABLEC (FONT_UF, "\\Psi ", "&Psi;"))
| "\\omega" -> LITERAL (HTMLABLEC (FONT_UF, "\\omega ", "&omega;"))
| "\\Omega" -> LITERAL (HTMLABLEC (FONT_UF, "\\Omega ", "&Omega;"))
| "\\xi" -> LITERAL (HTMLABLEC (FONT_UF, "\\xi ", "&xi;"))
| "\\Xi" -> LITERAL (HTMLABLEC (FONT_UF, "\\Xi ", "&Xi;"))
| "\\aleph" -> LITERAL (HTMLABLE (FONT_UF, "\\aleph ", "&alefsym;"))
| "\\alef" -> LITERAL (HTMLABLE (FONT_UF, "\\aleph ", "&alefsym;"))
| "\\alefsym" -> LITERAL (HTMLABLE (FONT_UF, "\\aleph ", "&alefsym;"))
| "\\larr" -> LITERAL (HTMLABLEM (FONT_UF, "\\leftarrow ", "&larr;"))
| "\\leftarrow" -> LITERAL (HTMLABLEM (FONT_UF, "\\leftarrow ", "&larr;"))
| "\\rarr" -> LITERAL (HTMLABLEM (FONT_UF, "\\rightarrow ", "&rarr;"))
| "\\to" -> LITERAL (HTMLABLEM (FONT_UF, "\\to ", "&rarr;"))
| "\\gets" -> LITERAL (HTMLABLEM (FONT_UF, "\\gets ", "&larr;"))
| "\\rightarrow" -> LITERAL (HTMLABLEM (FONT_UF, "\\rightarrow ", "&rarr;"))
| "\\longleftarrow" -> LITERAL (HTMLABLE (FONT_UF, "\\longleftarrow ", "&larr;"))
| "\\longrightarrow" -> LITERAL (HTMLABLE (FONT_UF, "\\longrightarrow ", "&rarr;"))
| "\\Larr" -> LITERAL (HTMLABLE (FONT_UF, "\\Leftarrow ", "&lArr;"))
| "\\lArr" -> LITERAL (HTMLABLE (FONT_UF, "\\Leftarrow ", "&lArr;"))
| "\\Leftarrow" -> LITERAL (HTMLABLE (FONT_UF, "\\Leftarrow ", "&lArr;"))
| "\\Rarr" -> LITERAL (HTMLABLE (FONT_UF, "\\Rightarrow ", "&rArr;"))
| "\\rArr" -> LITERAL (HTMLABLE (FONT_UF, "\\Rightarrow ", "&rArr;"))
| "\\Rightarrow" -> LITERAL (HTMLABLEM (FONT_UF, "\\Rightarrow ", "&rArr;"))
| "\\mapsto" -> LITERAL (HTMLABLE (FONT_UF, "\\mapsto ", "&rarr;"))
| "\\longmapsto" -> LITERAL (HTMLABLE (FONT_UF, "\\longmapsto ", "&rarr;"))
| "\\Longleftarrow" -> LITERAL (HTMLABLE (FONT_UF, "\\Longleftarrow ", "&lArr;"))
| "\\Longrightarrow" -> LITERAL (HTMLABLE (FONT_UF, "\\Longrightarrow ", "&rArr;"))
| "\\uarr" -> DELIMITER (HTMLABLEM (FONT_UF, "\\uparrow ", "&uarr;"))
| "\\uparrow" -> DELIMITER (HTMLABLEM (FONT_UF, "\\uparrow ", "&uarr;"))
| "\\uArr" -> DELIMITER (HTMLABLE (FONT_UF, "\\Uparrow ", "&uArr;"))
| "\\Uarr" -> DELIMITER (HTMLABLE (FONT_UF, "\\Uparrow ", "&uArr;"))
| "\\Uparrow" -> DELIMITER (HTMLABLE (FONT_UF, "\\Uparrow ", "&uArr;"))
| "\\darr" -> DELIMITER (HTMLABLEM (FONT_UF, "\\downarrow ", "&darr;"))
| "\\downarrow" -> DELIMITER (HTMLABLEM (FONT_UF, "\\downarrow ", "&darr;"))
| "\\dArr" -> DELIMITER (HTMLABLE (FONT_UF, "\\Downarrow ", "&dArr;"))
| "\\Darr" -> DELIMITER (HTMLABLE (FONT_UF, "\\Downarrow ", "&dArr;"))
| "\\Downarrow" -> DELIMITER (HTMLABLE (FONT_UF, "\\Downarrow ", "&dArr;"))
| "\\updownarrow" -> DELIMITER (TEX_ONLY "\\updownarrow ")
| "\\Updownarrow" -> DELIMITER (TEX_ONLY "\\Updownarrow ")
| "\\ulcorner" -> (tex_use_ams (); DELIMITER (TEX_ONLY "\\ulcorner "))
| "\\urcorner" -> (tex_use_ams (); DELIMITER (TEX_ONLY "\\urcorner "))
| "\\llcorner" -> (tex_use_ams (); DELIMITER (TEX_ONLY "\\llcorner "))
| "\\lrcorner" -> (tex_use_ams (); DELIMITER (TEX_ONLY "\\lrcorner "))
| "\\twoheadleftarrow" -> (tex_use_ams (); DELIMITER (TEX_ONLY "\\twoheadleftarrow "))
| "\\twoheadrightarrow" -> (tex_use_ams (); DELIMITER (TEX_ONLY "\\twoheadrightarrow "))
| "\\xleftarrow" -> (tex_use_ams (); FUN_AR1 "\\xleftarrow ")
| "\\xrightarrow" -> (tex_use_ams (); FUN_AR1 "\\xrightarrow ")
| "\\rightleftharpoons" -> DELIMITER (TEX_ONLY "\\rightleftharpoons ")
| "\\leftrightarrow" -> LITERAL (HTMLABLE (FONT_UF, "\\leftrightarrow ", "&harr;"))
| "\\lrarr" -> LITERAL (HTMLABLE (FONT_UF, "\\leftrightarrow ", "&harr;"))
| "\\harr" -> LITERAL (HTMLABLE (FONT_UF, "\\leftrightarrow ", "&harr;"))
| "\\Leftrightarrow" -> LITERAL (HTMLABLE (FONT_UF, "\\Leftrightarrow ", "&hArr;"))
| "\\Lrarr" -> LITERAL (HTMLABLE (FONT_UF, "\\Leftrightarrow ", "&hArr;"))
| "\\Harr" -> LITERAL (HTMLABLE (FONT_UF, "\\Leftrightarrow ", "&hArr;"))
| "\\lrArr" -> LITERAL (HTMLABLE (FONT_UF, "\\Leftrightarrow ", "&hArr;"))
| "\\hAar" -> LITERAL (HTMLABLE (FONT_UF, "\\Leftrightarrow ", "&hArr;"))
| "\\longleftrightarrow"->LITERAL (HTMLABLE (FONT_UF, "\\longleftrightarrow ", "&harr;"))
| "\\Longleftrightarrow"->LITERAL (HTMLABLE (FONT_UF, "\\Longleftrightarrow ", "&harr;"))
| "\\iff" -> LITERAL (HTMLABLE (FONT_UF, "\\iff ", "&harr;"))
| "\\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 ")
| "\\simeq" -> LITERAL (TEX_ONLY "\\simeq ")
| "\\ast" -> LITERAL (TEX_ONLY "\\ast ")
| "\\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 (HTMLABLEC(FONT_UFH,"\\ker ","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 (HTMLABLEC(FONT_UFH,"\\hom ","hom"))
| "\\arg" -> LITERAL (HTMLABLEC(FONT_UFH,"\\arg ","arg"))
| "\\dim" -> LITERAL (HTMLABLEC(FONT_UFH,"\\dim ","dim"))
| "\\inf" -> LITERAL (TEX_ONLY "\\inf ")
| "\\circ" -> LITERAL (TEX_ONLY "\\circ ")
| "\\hbar" -> LITERAL (TEX_ONLY "\\hbar ")
| "\\imath" -> LITERAL (TEX_ONLY "\\imath ")
| "\\jmath" -> LITERAL (TEX_ONLY "\\jmath ")
| "\\lnot" -> LITERAL (TEX_ONLY "\\lnot ")
| "\\hookrightarrow" -> LITERAL (TEX_ONLY "\\hookrightarrow ")
| "\\hookleftarrow" -> LITERAL (TEX_ONLY "\\hookleftarrow ")
| "\\mp" -> LITERAL (TEX_ONLY "\\mp ")
| "\\approx" -> LITERAL (HTMLABLE (FONT_UF, "\\approx ", "&asymp;"))
| "\\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 ", "&int;"))
| "\\sum" -> LITERAL (HTMLABLE_BIG ("\\sum ", "&sum;"))
| "\\prod" -> LITERAL (HTMLABLE_BIG ("\\prod ", "&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;"))
| "\\bull" -> LITERAL (HTMLABLE (FONT_UFH, "\\bullet ", "&bull;"))
| "\\angle" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UF, "\\angle ", "&ang;")))
| "\\dagger" -> LITERAL (HTMLABLEM(FONT_UFH, "\\dagger ", "&dagger;"))
| "\\ddagger" -> LITERAL (HTMLABLEM(FONT_UFH, "\\ddagger ", "&Dagger;"))
| "\\Dagger" -> LITERAL (HTMLABLEM(FONT_UFH, "\\ddagger ", "&Dagger;"))
| "\\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;"))
| "\\weierp" -> LITERAL (HTMLABLE (FONT_UF, "\\wp ", "&weierp;"))
| "\\wedge" -> LITERAL (HTMLABLE (FONT_UF, "\\wedge ", "&and;"))
| "\\and" -> LITERAL (HTMLABLE (FONT_UF, "\\land ", "&and;"))
| "\\land" -> LITERAL (HTMLABLE (FONT_UF, "\\land ", "&and;"))
| "\\vee" -> LITERAL (HTMLABLE (FONT_UF, "\\vee ", "&or;"))
| "\\or" -> LITERAL (HTMLABLE (FONT_UF, "\\lor ", "&or;"))
| "\\lor" -> LITERAL (HTMLABLE (FONT_UF, "\\lor ", "&or;"))
| "\\sub" -> LITERAL (HTMLABLE (FONT_UF, "\\subset ", "&sub;"))
| "\\supe" -> LITERAL (HTMLABLE (FONT_UF, "\\supseteq ", "&supe;"))
| "\\sube" -> LITERAL (HTMLABLE (FONT_UF, "\\subseteq ", "&sube;"))
| "\\supset" -> LITERAL (HTMLABLE (FONT_UF, "\\supset ", "&sup;"))
| "\\subset" -> LITERAL (HTMLABLE (FONT_UF, "\\subset ", "&sub;"))
| "\\supseteq" -> LITERAL (HTMLABLE (FONT_UF, "\\supseteq ", "&supe;"))
| "\\subseteq" -> LITERAL (HTMLABLE (FONT_UF, "\\subseteq ", "&sube;"))
| "\\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 ", "&perp;"))
| "\\bot" -> LITERAL (HTMLABLE (FONT_UF, "\\bot ", "&perp;"))
| "\\lfloor" -> DELIMITER (HTMLABLE (FONT_UF, "\\lfloor ", "&lfloor;"))
| "\\rfloor" -> DELIMITER (HTMLABLE (FONT_UF, "\\rfloor ", "&rfloor;"))
| "\\lceil" -> DELIMITER (HTMLABLE (FONT_UF, "\\lceil ", "&lceil;"))
| "\\rceil" -> DELIMITER (HTMLABLE (FONT_UF, "\\rceil ", "&rceil;"))
| "\\lbrace" -> DELIMITER (HTMLABLEC(FONT_UFH, "\\lbrace ", "{"))
| "\\rbrace" -> DELIMITER (HTMLABLEC(FONT_UFH, "\\rbrace ", "}"))
| "\\infty" -> LITERAL (HTMLABLEM(FONT_UF, "\\infty ", "&infin;"))
| "\\infin" -> LITERAL (HTMLABLEM(FONT_UF, "\\infty ", "&infin;"))
| "\\isin" -> LITERAL (HTMLABLE (FONT_UF, "\\in ", "&isin;"))
| "\\in" -> LITERAL (HTMLABLE (FONT_UF, "\\in ", "&isin;"))
| "\\ni" -> LITERAL (HTMLABLE (FONT_UF, "\\ni ", "&ni;"))
| "\\notin" -> LITERAL (HTMLABLE (FONT_UF, "\\notin ", "&notin;"))
| "\\smallsetminus" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\smallsetminus "))
| "\\And" -> (tex_use_ams (); LITERAL (HTMLABLEM(FONT_UFH, "\\And ", "&nbsp;&amp;&nbsp;")))
| "\\forall" -> LITERAL (HTMLABLE (FONT_UFH, "\\forall ", "&forall;"))
| "\\exists" -> LITERAL (HTMLABLE (FONT_UFH, "\\exists ", "&exist;"))
| "\\exist" -> LITERAL (HTMLABLE (FONT_UFH, "\\exists ", "&exist;"))
| "\\equiv" -> LITERAL (HTMLABLEM(FONT_UFH, "\\equiv ", "&equiv;"))
| "\\ne" -> LITERAL (HTMLABLEM(FONT_UFH, "\\neq ", "&ne;"))
| "\\neq" -> LITERAL (HTMLABLEM(FONT_UFH, "\\neq ", "&ne;"))
| "\\Re" -> LITERAL (HTMLABLE (FONT_UF, "\\Re ", "&real;"))
| "\\real" -> LITERAL (HTMLABLE (FONT_UF, "\\Re ", "&real;"))
| "\\Im" -> LITERAL (HTMLABLE (FONT_UF, "\\Im ", "&image;"))
| "\\image" -> LITERAL (HTMLABLE (FONT_UF, "\\Im ", "&image;"))
| "\\prime" -> LITERAL (HTMLABLE (FONT_UFH,"\\prime ", "&prime;"))
| "\\backslash" -> DELIMITER (HTMLABLEM(FONT_UFH,"\\backslash ", "\\"))
| "\\setminus" -> LITERAL (HTMLABLEM(FONT_UFH,"\\setminus ", "\\"))
| "\\times" -> LITERAL (HTMLABLEM(FONT_UFH,"\\times ", "&times;"))
| "\\pm" -> LITERAL (HTMLABLEM(FONT_UFH,"\\pm ", "&plusmn;"))
| "\\plusmn" -> LITERAL (HTMLABLEM(FONT_UFH,"\\pm ", "&plusmn;"))
| "\\cdot" -> LITERAL (HTMLABLE (FONT_UFH,"\\cdot ", "&sdot;"))
| "\\AA" -> LITERAL (HTMLABLE (FONT_UFH,"\\AA ", "&Aring;"))
| "\\cdots" -> LITERAL (HTMLABLE (FONT_UFH,"\\cdots ", "&sdot;&sdot;&sdot;"))
| "\\sdot" -> LITERAL (HTMLABLE (FONT_UFH,"\\cdot ", "&sdot;"))
| "\\oplus" -> LITERAL (HTMLABLE (FONT_UF, "\\oplus ", "&oplus;"))
| "\\otimes" -> LITERAL (HTMLABLE (FONT_UF, "\\otimes ", "&otimes;"))
| "\\cap" -> LITERAL (HTMLABLEM(FONT_UF, "\\cap ", "&cap;"))
| "\\cup" -> LITERAL (HTMLABLE (FONT_UF, "\\cup ", "&cup;"))
| "\\uplus" -> LITERAL (TEX_ONLY "\\uplus ")
| "\\sqcap" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\sqcap "))
| "\\sqcup" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\sqcup "))
| "\\empty" -> LITERAL (HTMLABLE (FONT_UF, "\\emptyset ", "&empty;"))
| "\\emptyset" -> LITERAL (HTMLABLE (FONT_UF, "\\emptyset ", "&empty;"))
| "\\O" -> LITERAL (HTMLABLE (FONT_UF, "\\emptyset ", "&empty;"))
| "\\S" -> LITERAL (HTMLABLEM(FONT_UFH,"\\S ", "&sect;"))
| "\\sect" -> LITERAL (HTMLABLEM(FONT_UFH,"\\S ", "&sect;"))
| "\\nabla" -> LITERAL (HTMLABLE (FONT_UF, "\\nabla ", "&nabla;"))
| "\\geq" -> LITERAL (HTMLABLE (FONT_UFH,"\\geq ", "&ge;"))
| "\\ge" -> LITERAL (HTMLABLE (FONT_UFH,"\\geq ", "&ge;"))
| "\\leq" -> LITERAL (HTMLABLE (FONT_UFH,"\\leq ", "&le;"))
| "\\le" -> LITERAL (HTMLABLE (FONT_UFH,"\\leq ", "&le;"))
| "\\cong" -> LITERAL (HTMLABLE (FONT_UF, "\\cong ", "&cong;"))
| "\\ang" -> LITERAL (HTMLABLE (FONT_UF, "\\angle ", "&ang;"))
| "\\part" -> LITERAL (HTMLABLEM(FONT_UF, "\\partial ", "&part;"))
| "\\partial" -> LITERAL (HTMLABLEM(FONT_UF, "\\partial ", "&part;"))
| "\\ldots" -> LITERAL (HTMLABLEM(FONT_UFH,"\\ldots ", "..."))
| "\\dots" -> LITERAL (HTMLABLEM(FONT_UFH,"\\dots ", "..."))
| "\\quad" -> LITERAL (HTMLABLE (FONT_UF, "\\quad ","&nbsp;&nbsp;"))
| "\\qquad" -> LITERAL (HTMLABLE (FONT_UF, "\\qquad ","&nbsp;&nbsp;&nbsp;&nbsp;"))
| "\\mid" -> LITERAL (HTMLABLEM(FONT_UFH,"\\mid ", " | "))
| "\\neg" -> LITERAL (HTMLABLEM(FONT_UFH,"\\neg ", "&not;"))
| "\\langle" -> DELIMITER (HTMLABLE (FONT_UFH,"\\langle ","&lang;"))
| "\\rangle" -> DELIMITER (HTMLABLE (FONT_UFH,"\\rangle ","&rang;"))
| "\\lang" -> DELIMITER (HTMLABLE (FONT_UFH,"\\langle ","&lang;"))
| "\\rang" -> DELIMITER (HTMLABLE (FONT_UFH,"\\rangle ","&rang;"))
| "\\lbrack" -> DELIMITER (HTMLABLEC(FONT_UFH,"[","["))
| "\\rbrack" -> DELIMITER (HTMLABLEC(FONT_UFH,"]","]"))
| "\\surd" -> LITERAL (TEX_ONLY "\\surd ")
| "\\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 ")
| "\\diamond" -> LITERAL (TEX_ONLY "\\diamond ")
| "\\bigtriangleup" -> LITERAL (TEX_ONLY "\\bigtriangleup ")
| "\\bigtriangledown" -> LITERAL (TEX_ONLY "\\bigtriangledown ")
| "\\diamondsuit" -> LITERAL (TEX_ONLY "\\diamondsuit ")
| "\\ominus" -> LITERAL (TEX_ONLY "\\ominus ")
| "\\oslash" -> LITERAL (TEX_ONLY "\\oslash ")
| "\\odot" -> LITERAL (TEX_ONLY "\\odot ")
| "\\bigcirc" -> LITERAL (TEX_ONLY "\\bigcirc ")
| "\\amalg" -> LITERAL (TEX_ONLY "\\amalg ")
| "\\prec" -> LITERAL (TEX_ONLY "\\prec ")
| "\\succ" -> LITERAL (TEX_ONLY "\\succ ")
| "\\preceq" -> LITERAL (TEX_ONLY "\\preceq ")
| "\\succeq" -> LITERAL (TEX_ONLY "\\succeq ")
| "\\dashv" -> LITERAL (TEX_ONLY "\\dashv ")
| "\\asymp" -> LITERAL (TEX_ONLY "\\asymp ")
| "\\doteq" -> LITERAL (TEX_ONLY "\\doteq ")
| "\\parallel" -> LITERAL (TEX_ONLY "\\parallel ")
| "\\implies" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UF, "\\implies ", "&rArr;")))
| "\\mod" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mod ", "mod")))
| "\\Diamond" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UF, "\\Diamond ", "&loz;")))
| "\\dotsb" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UF, "\\dotsb ", "&sdot;&sdot;&sdot;")))
| "\\dotsc" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UF, "\\dotsc ", "...")))
| "\\dotsi" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UF, "\\dotsi ", "&sdot;&sdot;&sdot;")))
| "\\dotsm" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UF, "\\dotsm ", "&sdot;&sdot;&sdot;")))
| "\\dotso" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UF, "\\dotso ", "...")))
| "\\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>")))
| "\\C" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{C}", "<b>C</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>")))
| "\\Q" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{Q}", "<b>Q</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 "))
| "\\restriction" -> (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 "
| "\\hline" -> LITERAL (TEX_ONLY "\\hline ")
| "\\vline" -> LITERAL (TEX_ONLY "\\vline ")
| "\\widehat" -> LITERAL (TEX_ONLY "\\widehat ")
| "\\overline" -> LITERAL (TEX_ONLY "\\overline ")
| "\\overbrace" -> LITERAL (TEX_ONLY "\\overbrace ")
| "\\underline" -> LITERAL (TEX_ONLY "\\underline ")
| "\\underbrace" -> LITERAL (TEX_ONLY "\\underbrace ")
| "\\overleftarrow" -> LITERAL (TEX_ONLY "\\overleftarrow ")
| "\\overrightarrow" -> LITERAL (TEX_ONLY "\\overrightarrow ")
| "\\overleftrightarrow"-> (tex_use_ams(); LITERAL (TEX_ONLY "\\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" -> (tex_use_ams (); FUN_AR2 "\\binom ")
| "\\dbinom" -> (tex_use_ams (); FUN_AR2 "\\dbinom ")
| "\\tbinom" -> (tex_use_ams (); FUN_AR2 "\\tbinom ")
| "\\stackrel" -> FUN_AR2 "\\stackrel "
| "\\sideset" -> (tex_use_ams (); FUN_AR2nb "\\sideset ")
| "\\underset" -> (tex_use_ams (); FUN_AR2 "\\underset ")
| "\\overset" -> (tex_use_ams (); FUN_AR2 "\\overset ")
| "\\frac" -> FUN_AR2h ("\\frac ", fun num den -> Html.html_render [num], "<hr style=\"{background: black}\"/>", Html.html_render [den])
| "\\dfrac" -> (tex_use_ams () ; FUN_AR2 "\\dfrac ")
| "\\tfrac" -> (tex_use_ams () ; FUN_AR2h ("\\tfrac ", 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 "
| "\\cancel" -> FUN_AR1 "\\cancel "
| "\\bcancel" -> FUN_AR1 "\\bcancel "
| "\\xcancel" -> FUN_AR1 "\\xcancel "
| "\\cancelto" -> FUN_AR2 "\\cancelto "
| "\\pmod" -> FUN_AR1hl ("\\pmod ", ("(mod ", ")"))
| "\\bmod" -> FUN_AR1hl ("\\bmod ", ("mod ", ""))
| "\\emph" -> FUN_AR1 "\\emph "
| "\\texttt" -> FUN_AR1 "\\texttt "
| "\\textbf" -> FUN_AR1 "\\textbf "
| "\\textsf" -> FUN_AR1 "\\textsf "
| "\\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 "
| "\\bigl" -> (tex_use_ams ();BIG "\\bigl ")
| "\\bigr" -> (tex_use_ams ();BIG "\\bigr ")
| "\\Bigl" -> (tex_use_ams ();BIG "\\Bigl ")
| "\\Bigr" -> (tex_use_ams ();BIG "\\Bigr ")
| "\\biggl" -> (tex_use_ams ();BIG "\\biggl ")
| "\\biggr" -> (tex_use_ams ();BIG "\\biggr ")
| "\\Biggl" -> (tex_use_ams ();BIG "\\Biggl ")
| "\\Biggr" -> (tex_use_ams ();BIG "\\Biggr ")
| "\\vartriangle" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\vartriangle "))
| "\\triangledown" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\triangledown "))
| "\\lozenge" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\lozenge "))
| "\\circledS" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\circledS "))
| "\\measuredangle" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\measuredangle "))
| "\\nexists" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nexists "))
| "\\Bbbk" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Bbbk "))
| "\\backprime" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\backprime "))
| "\\blacktriangle" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\blacktriangle "))
| "\\blacktriangledown"-> (tex_use_ams (); LITERAL (TEX_ONLY "\\blacktriangledown "))
| "\\blacksquare" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\blacksquare "))
| "\\blacklozenge" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\blacklozenge "))
| "\\bigstar" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\bigstar "))
| "\\sphericalangle" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\sphericalangle "))
| "\\diagup" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\diagup "))
| "\\diagdown" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\diagdown "))
| "\\dotplus" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\dotplus "))
| "\\Cap" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Cap "))
| "\\doublecap" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Cap "))
| "\\Cup" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Cup "))
| "\\doublecup" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Cup "))
| "\\barwedge" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\barwedge "))
| "\\veebar" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\veebar "))
| "\\doublebarwedge" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\doublebarwedge "))
| "\\boxminus" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\boxminus "))
| "\\boxtimes" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\boxtimes "))
| "\\boxdot" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\boxdot "))
| "\\boxplus" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\boxplus "))
| "\\divideontimes" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\divideontimes "))
| "\\ltimes" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\ltimes "))
| "\\rtimes" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\rtimes "))
| "\\leftthreetimes" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\leftthreetimes "))
| "\\rightthreetimes" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\rightthreetimes "))
| "\\curlywedge" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\curlywedge "))
| "\\curlyvee" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\curlyvee "))
| "\\circleddash" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\circleddash "))
| "\\circledast" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\circledast "))
| "\\circledcirc" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\circledcirc "))
| "\\centerdot" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\centerdot "))
| "\\intercal" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\intercal "))
| "\\leqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\leqq "))
| "\\leqslant" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\leqslant "))
| "\\eqslantless" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\eqslantless "))
| "\\lessapprox" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\lessapprox "))
| "\\approxeq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\approxeq "))
| "\\lessdot" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\lessdot "))
| "\\lll" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\lll "))
| "\\lessgtr" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\lessgtr "))
| "\\lesseqgtr" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\lesseqgtr "))
| "\\lesseqqgtr" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\lesseqqgtr "))
| "\\doteqdot" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\doteqdot "))
| "\\Doteq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\doteqdot "))
| "\\risingdotseq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\risingdotseq "))
| "\\fallingdotseq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\fallingdotseq "))
| "\\backsim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\backsim "))
| "\\backsimeq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\backsimeq "))
| "\\subseteqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\subseteqq "))
| "\\Subset" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Subset "))
| "\\preccurlyeq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\preccurlyeq "))
| "\\curlyeqprec" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\curlyeqprec "))
| "\\precsim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\precsim "))
| "\\precapprox" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\precapprox "))
| "\\vartriangleleft" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\vartriangleleft "))
| "\\Vvdash" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Vvdash "))
| "\\bumpeq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\bumpeq "))
| "\\Bumpeq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Bumpeq "))
| "\\geqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\geqq "))
| "\\geqslant" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\geqslant "))
| "\\eqslantgtr" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\eqslantgtr "))
| "\\gtrsim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\gtrsim "))
| "\\gtrapprox" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\gtrapprox "))
| "\\eqsim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\eqsim "))
| "\\gtrdot" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\gtrdot "))
| "\\ggg" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\ggg "))
| "\\gggtr" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\ggg "))
| "\\gtrless" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\gtrless "))
| "\\gtreqless" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\gtreqless "))
| "\\gtreqqless" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\gtreqqless "))
| "\\eqcirc" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\eqcirc "))
| "\\circeq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\circeq "))
| "\\triangleq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\triangleq "))
| "\\thicksim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\thicksim "))
| "\\thickapprox" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\thickapprox "))
| "\\supseteqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\supseteqq "))
| "\\Supset" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Supset "))
| "\\succcurlyeq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\succcurlyeq "))
| "\\curlyeqsucc" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\curlyeqsucc "))
| "\\succsim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\succsim "))
| "\\succapprox" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\succapprox "))
| "\\vartriangleright" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\vartriangleright "))
| "\\shortmid" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\shortmid "))
| "\\shortparallel" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\shortparallel "))
| "\\between" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\between "))
| "\\pitchfork" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\pitchfork "))
| "\\varpropto" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\varpropto "))
| "\\blacktriangleleft"-> (tex_use_ams (); LITERAL (TEX_ONLY "\\blacktriangleleft "))
| "\\therefore" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\therefore "))
| "\\backepsilon" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\backepsilon "))
| "\\blacktriangleright"-> (tex_use_ams (); LITERAL (TEX_ONLY "\\blacktriangleright "))
| "\\because" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\because "))
| "\\nleqslant" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nleqslant "))
| "\\nleqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nleqq "))
| "\\lneq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\lneq "))
| "\\lneqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\lneqq "))
| "\\lvertneqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\lvertneqq "))
| "\\lnsim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\lnsim "))
| "\\lnapprox" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\lnapprox "))
| "\\nprec" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nprec "))
| "\\npreceq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\npreceq "))
| "\\precneqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\precneqq "))
| "\\precnsim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\precnsim "))
| "\\precnapprox" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\precnapprox "))
| "\\nsim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nsim "))
| "\\nshortmid" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nshortmid "))
| "\\nvdash" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nvdash "))
| "\\nVdash" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nVdash "))
| "\\ntriangleleft" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\ntriangleleft "))
| "\\ntrianglelefteq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\ntrianglelefteq "))
| "\\nsubseteq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nsubseteq "))
| "\\nsubseteqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nsubseteqq "))
| "\\varsubsetneq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\varsubsetneq "))
| "\\subsetneqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\subsetneqq "))
| "\\varsubsetneqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\varsubsetneqq "))
| "\\ngtr" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\ngtr "))
| "\\ngeqslant" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\ngeqslant "))
| "\\ngeqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\ngeqq "))
| "\\gneq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\gneq "))
| "\\gneqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\gneqq "))
| "\\gvertneqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\gvertneqq "))
| "\\gnsim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\gnsim "))
| "\\gnapprox" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\gnapprox "))
| "\\nsucc" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nsucc "))
| "\\nsucceq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nsucceq "))
| "\\succneqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\succneqq "))
| "\\succnsim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\succnsim "))
| "\\succnapprox" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\succnapprox "))
| "\\ncong" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\ncong "))
| "\\nshortparallel" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nshortparallel "))
| "\\nparallel" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nparallel "))
| "\\nvDash" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nvDash "))
| "\\nVDash" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nVDash "))
| "\\ntriangleright" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\ntriangleright "))
| "\\ntrianglerighteq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\ntrianglerighteq "))
| "\\nsupseteq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nsupseteq "))
| "\\nsupseteqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nsupseteqq "))
| "\\varsupsetneq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\varsupsetneq "))
| "\\supsetneqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\supsetneqq "))
| "\\varsupsetneqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\varsupsetneqq "))
| "\\leftleftarrows" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\leftleftarrows "))
| "\\leftrightarrows" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\leftrightarrows "))
| "\\Lleftarrow" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Lleftarrow "))
| "\\leftarrowtail" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\leftarrowtail "))
| "\\looparrowleft" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\looparrowleft "))
| "\\leftrightharpoons"-> (tex_use_ams (); LITERAL (TEX_ONLY "\\leftrightharpoons "))
| "\\curvearrowleft" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\curvearrowleft "))
| "\\circlearrowleft" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\circlearrowleft "))
| "\\Lsh" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Lsh "))
| "\\upuparrows" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\upuparrows "))
| "\\rightrightarrows" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\rightrightarrows "))
| "\\rightleftarrows" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\rightleftarrows "))
| "\\Rrightarrow" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Rrightarrow "))
| "\\rightarrowtail" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\rightarrowtail "))
| "\\looparrowright" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\looparrowright "))
| "\\curvearrowright" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\curvearrowright "))
| "\\circlearrowright" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\circlearrowright "))
| "\\Rsh" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Rsh "))
| "\\downdownarrows" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\downdownarrows "))
| "\\multimap" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\multimap "))
| "\\leftrightsquigarrow"-> (tex_use_ams (); LITERAL (TEX_ONLY "\\leftrightsquigarrow "))
| "\\rightsquigarrow" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\rightsquigarrow "))
| "\\nLeftarrow" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nLeftarrow "))
| "\\nleftrightarrow" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nleftrightarrow "))
| "\\nRightarrow" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nRightarrow "))
| "\\nLeftrightarrow" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nLeftrightarrow "))
| "\\mathit" -> (tex_use_ams (); FUN_AR1hf ("\\mathit ", FONTFORCE_IT))
| "\\mathrm" -> (tex_use_ams (); FUN_AR1hf ("\\mathrm ", FONTFORCE_RM))
| "\\mathord" -> (tex_use_ams (); FUN_AR1 "\\mathord ")
| "\\mathop" -> (tex_use_ams (); FUN_AR1 "\\mathop ")
| "\\mathbin" -> (tex_use_ams (); FUN_AR1 "\\mathbin ")
| "\\mathrel" -> (tex_use_ams (); FUN_AR1 "\\mathrel ")
| "\\mathopen" -> (tex_use_ams (); FUN_AR1 "\\mathopen ")
| "\\mathclose" -> (tex_use_ams (); FUN_AR1 "\\mathclose ")
| "\\mathpunct" -> (tex_use_ams (); FUN_AR1 "\\mathpunct ")
| "\\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 ")
| "\\mathtt" -> (tex_use_ams (); FUN_AR1 "\\mathtt ")
| "\\mathfrak" -> (tex_use_ams (); FUN_AR1 "\\mathfrak ")
| "\\operatorname" -> (tex_use_ams (); FUN_AR1 "\\operatorname ")
| "\\text" -> raise (Failure "malformatted \\text")
| "\\mbox" -> raise (Failure "malformatted \\mbox")
| "\\vbox" -> raise (Failure "malformatted \\vbox")
| "\\hbox" -> raise (Failure "malformatted \\hbox")
| "\\color" -> (tex_use_color (); LITERAL (TEX_ONLY "\\color"))
| "\\pagecolor" -> (tex_use_color (); LITERAL (TEX_ONLY "\\pagecolor"))
| "\\definecolor" -> (tex_use_color (); LITERAL (TEX_ONLY "\\definecolor"))
| s -> raise (Illegal_tex_function s)

11
math/texutil.mli Normal file
View File

@ -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

58
math/texvc.ml Normal file
View File

@ -0,0 +1,58 @@
(* vim: set sw=8 ts=8 et: *)
exception LexerException of string
(* *)
let lexer_token_safe lexbuf =
try Lexer.token lexbuf
with Failure s -> raise (LexerException s)
(* *)
let render tmppath finalpath tree backcolor =
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 backcolor
end
(* TODO: document
* Arguments:
* 1st :
* 2nd :
* 3rd :
* 4th : encoding (Default: UTF-8)
* 5th : color (Default: rgb 1.0 1.0 1.0)
*
* Output one character:
* S : Parsing error
* E : Lexer exception raised
* F : TeX function not recognized
* - : Generic/Default failure code. Might be an invalid argument,
* output file already exist, a problem with an external
* command ...
* *)
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))
) (try Sys.argv.(5) with _ -> "rgb 1.0 1.0 1.0")
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 "-"

62
math/texvc_cgi.ml Normal file
View File

@ -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

24
math/texvc_test.ml Normal file
View File

@ -0,0 +1,24 @@
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
(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 ();;

3
math/texvc_tex.ml Normal file
View File

@ -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 _ -> ()

26
math/util.ml Normal file
View File

@ -0,0 +1,26 @@
(* vim: set sw=8 ts=8 et: *)
(* TODO document *)
let mapjoin f l = (List.fold_left (fun a b -> a ^ (f b)) "" l)
(* TODO document *)
let mapjoine e f = function
[] -> ""
| h::t -> (List.fold_left (fun a b -> a ^ e ^ (f b)) (f h) t)
(* Exception used by open_out_unless_exists below *)
exception FileAlreadyExists
(* Wrapper which raise an exception when output path already exist *)
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)
)

41
mathParserTests.txt Normal file
View File

@ -0,0 +1,41 @@
!! test
pre-save transform: comment containing math
!! options
pst
!! input
<!-- <math>data</math> -->
!!result
<!-- <math>data</math> -->
!!end
#!! test
#BUG 1887: A <math> with a thumbnail- we don't render math in the parsertests by default,
#so math is not stripped and turns up as escaped &lt;math&gt; tags.
#!! input
#[[Image:foobar.jpg|thumb|<math>2+2</math>]]
#!! result
#<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/3/3a/Foobar.jpg" width="180" height="20" class="thumbimage" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div>&lt;math&gt;2+2&lt;/math&gt;</div></div></div>
#
#!! end
!! test
BUG 1887, part 2: A <math> with a thumbnail- math enabled
!! options
math
!! input
[[Image:foobar.jpg|thumb|<math>2+2</math>]]
!! result
<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/3/3a/Foobar.jpg" width="180" height="20" class="thumbimage" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div><span class="texhtml" dir="ltr">2 + 2</span></div></div></div>
!! end
#!! test
#Math section safety when disabled
#!! input
#<math><script>alert(document.cookies);</script></math>
#!! result
#<p>&lt;math&gt;&lt;script&gt;alert(document.cookies);&lt;/script&gt;&lt;/math&gt;
#</p>
#!! end