*
*/
if(!defined('DOKU_INC')) die();
if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
require_once(DOKU_PLUGIN.'syntax.php');
class syntax_plugin_masciimath extends DokuWiki_Syntax_Plugin {
public $syms;
public $parsestr;
function getType(){ return 'substition'; }
function getSort(){ return 300; }
function connectTo($mode) { $this->Lexer->addSpecialPattern('`.*?`',$mode,'plugin_masciimath'); }
function setup_syms() {
$this->syms = array(
# Array of associative arrays, der rummer disse keys:
# 'ascii' er token i rå ascii-form
# 'ml' er token på string-form, med evt yderste parantes bevaret
# 'ml_nobr' er token på string-form med evt yderste parantes skrællet af (medmindre det er pipes)
# 'ml_sign' og 'ml_op' er kode for symboler i sekundær rolle, som sign (unært minus) og som svag operator (pipe)
# 'row' er token som array af komma-separerede elementer (kun til brug for matrix-logikken)
# 'type' bestemmer en operators type:
# 'op' er minimal præ- eller infix-operator der står som symbol i en row; parseren opfatter et påfølgende minus som unær operator
# 'leftbracket' og 'rightbracket' er parantestegn, dog ikke '|' som får særbehandling
# 'infix' er operatorer som ^, _, /, og //
# 'unary' er operatorer som sqrt, hat og fr
# 'binary' er operatorer som 'root' og 'stackrel'
# 'func' er operatorer som sin, cos og lim (der binder stærkt)
# 'magnum' er operatorer som int, sum og prod (der binder svagt)
# 'underover' er sand for operatorer som prod og lim, der foretrækker at have sub/super-script stående "under/over" sig
# 'wrap_left' og 'wrap_right' forklarer hvordan en operator implementeres
// Signs ('sign')
array ('ascii' => '+', 'ml' => '+', 'type' => 'sign', 'ml_sign' => '+'),
array ('ascii' => '+ ', 'ml' => '+'),
array ('ascii' => '-', 'ml' => '−', 'type' => 'sign', 'ml_sign' => '‐'), # ‐ is HYPHEN
array ('ascii' => '- ', 'ml' => '−'),
array ('ascii' => '+-', 'ml' => '±', 'type' => 'sign', 'ml_sign' => '±'),
array ('ascii' => '+- ', 'ml' => '±'),
// Symbolic operators ('op')
array ('ascii' => ',', 'ml' => ',', 'type' => 'op'),
array ('ascii' => ':', 'ml' => ':', 'type' => 'op'),
array ('ascii' => ';', 'ml' => ';', 'type' => 'op'),
array ('ascii' => '=', 'ml' => '=', 'type' => 'op'),
array ('ascii' => '\\\\', 'ml' => '\', 'type' => 'op'), # backslash
array ('ascii' => '\ ', 'ml' => ' ', 'type' => 'op'),
array ('ascii' => '*', 'ml' => '⋅', 'type' => 'op'),
array ('ascii' => '**', 'ml' => '⋆', 'type' => 'op'),
array ('ascii' => 'xx', 'ml' => '×', 'type' => 'op'),
array ('ascii' => 'times', 'ml' => '×', 'type' => 'op'),
array ('ascii' => '-:', 'ml' => '÷', 'type' => 'op'),
array ('ascii' => '@', 'ml' => '∘', 'type' => 'op'),
array ('ascii' => 'o+', 'ml' => '⊕', 'type' => 'op'),
array ('ascii' => 'ox', 'ml' => '⊗', 'type' => 'op'),
array ('ascii' => 'o.', 'ml' => '⊙', 'type' => 'op'),
array ('ascii' => '^^', 'ml' => '∧', 'type' => 'op'),
array ('ascii' => 'vv', 'ml' => '∨', 'type' => 'op'),
array ('ascii' => 'nn', 'ml' => '∩', 'type' => 'op'),
array ('ascii' => 'uu', 'ml' => '∪', 'type' => 'op'),
array ('ascii' => '!=', 'ml' => '≠', 'type' => 'op'),
array ('ascii' => 'ne', 'ml' => '≠', 'type' => 'op'),
array ('ascii' => '<', 'ml' => '<', 'type' => 'op'),
array ('ascii' => 'lt', 'ml' => '<', 'type' => 'op'),
array ('ascii' => '>', 'ml' => '>', 'type' => 'op'),
array ('ascii' => 'gt', 'ml' => '>', 'type' => 'op'),
array ('ascii' => '<=', 'ml' => '≤', 'type' => 'op'),
array ('ascii' => 'le', 'ml' => '≤', 'type' => 'op'),
array ('ascii' => '>=', 'ml' => '≥', 'type' => 'op'),
array ('ascii' => 'ge', 'ml' => '≥', 'type' => 'op'),
array ('ascii' => '<<', 'ml' => '≪', 'type' => 'op'),
array ('ascii' => '>>', 'ml' => '≫', 'type' => 'op'),
array ('ascii' => '>-', 'ml' => '≻', 'type' => 'op'),
array ('ascii' => '-<', 'ml' => '≺', 'type' => 'op'),
array ('ascii' => 'in', 'ml' => '∈', 'type' => 'op'),
array ('ascii' => '!in', 'ml' => '∉', 'type' => 'op'),
array ('ascii' => 'sub', 'ml' => '⊂', 'type' => 'op'),
array ('ascii' => 'sup', 'ml' => '⊃', 'type' => 'op'),
array ('ascii' => '!sub', 'ml' => '⊄', 'type' => 'op'),
array ('ascii' => 'nsub', 'ml' => '⊄', 'type' => 'op'),
array ('ascii' => 'sube', 'ml' => '⊆', 'type' => 'op'),
array ('ascii' => 'supe', 'ml' => '⊇', 'type' => 'op'),
array ('ascii' => '-=', 'ml' => '≡', 'type' => 'op'),
array ('ascii' => '~=', 'ml' => '≅', 'type' => 'op'),
array ('ascii' => '~~', 'ml' => '≈', 'type' => 'op'),
array ('ascii' => 'approx', 'ml' => '≈', 'type' => 'op'),
array ('ascii' => 'prop', 'ml' => '∝', 'type' => 'op'),
array ('ascii' => 'not', 'ml' => '¬', 'type' => 'op'),
array ('ascii' => 'AA', 'ml' => '∀', 'type' => 'op'),
array ('ascii' => 'EE', 'ml' => '∃', 'type' => 'op'),
array ('ascii' => '|--', 'ml' => '⊢', 'type' => 'op'),
array ('ascii' => '|==', 'ml' => '⊨', 'type' => 'op'),
array ('ascii' => '/_', 'ml' => '∠', 'type' => 'op'),
array ('ascii' => 'ang', 'ml' => '∠', 'type' => 'op'),
array ('ascii' => ':.', 'ml' => '∴', 'type' => 'op'),
array ('ascii' => '<-', 'ml' => '←', 'type' => 'op'),
array ('ascii' => 'larr', 'ml' => '←', 'type' => 'op'),
array ('ascii' => 'uarr', 'ml' => '↑', 'type' => 'op'),
array ('ascii' => 'rarr', 'ml' => '→', 'type' => 'op'),
array ('ascii' => '->', 'ml' => '→', 'type' => 'op'),
array ('ascii' => 'darr', 'ml' => '↓', 'type' => 'op'),
array ('ascii' => '<->', 'ml' => '↔', 'type' => 'op'),
array ('ascii' => 'harr', 'ml' => '↔', 'type' => 'op'),
array ('ascii' => '|->', 'ml' => '↦', 'type' => 'op'),
array ('ascii' => 'rArr', 'ml' => '⇒', 'type' => 'op'),
array ('ascii' => '=>', 'ml' => '⇒', 'type' => 'op'),
array ('ascii' => 'lArr', 'ml' => '⇐', 'type' => 'op'),
array ('ascii' => 'hArr', 'ml' => '⇔', 'type' => 'op'),
array ('ascii' => 'iff', 'ml' => '⇔', 'type' => 'op'),
array ('ascii' => '<=>', 'ml' => '⇔', 'type' => 'op'),
array ('ascii' => '|__', 'ml' => '⌊', 'type' => 'op'),
array ('ascii' => '__|', 'ml' => '⌋', 'type' => 'op'),
array ('ascii' => '|~', 'ml' => '⌈', 'type' => 'op'),
array ('ascii' => '~|', 'ml' => '⌉', 'type' => 'op'),
array ('ascii' => 'if', 'ml' => 'if', 'type' => 'op'),
array ('ascii' => 'and', 'ml' => 'and', 'type' => 'op'),
array ('ascii' => 'or', 'ml' => 'or', 'type' => 'op'),
// Brackets ('leftbracket' and 'rightbracket')
array ('ascii' => '(', 'ml' => '(', 'type' => 'leftbracket'),
array ('ascii' => ')', 'ml' => ')', 'type' => 'rightbracket'),
array ('ascii' => '[', 'ml' => '[', 'type' => 'leftbracket'),
array ('ascii' => ']', 'ml' => ']', 'type' => 'rightbracket'),
array ('ascii' => '{', 'ml' => '{', 'type' => 'leftbracket'),
array ('ascii' => '}', 'ml' => '}', 'type' => 'rightbracket'),
array ('ascii' => '(:', 'ml' => '〈', 'type' => 'leftbracket'),
array ('ascii' => ':)', 'ml' => '〉', 'type' => 'rightbracket'),
array ('ascii' => '{:', 'ml' => '', 'type' => 'leftbracket'),
array ('ascii' => ':}', 'ml' => '', 'type' => 'rightbracket'),
array ('ascii' => '|', 'ml' => '|', 'ml_op' => '|'),
// Special operators
array ('ascii' => '^', 'ml' => '^', 'type' => 'infix', 'wrap_left' => '', 'wrap_right' => ''),
array ('ascii' => '_', 'ml' => '_', 'type' => 'infix', 'wrap_left' => '', 'wrap_right' => ''),
array ('ascii' => '/', 'ml' => '/', 'type' => 'infix', 'wrap_left' => '', 'wrap_right' => ''),
array ('ascii' => '//', 'ml' => '⁄', 'type' => 'infix', 'wrap_left' => '', 'wrap_right' => ''),
array ('ascii' => 'sqrt', 'type' => 'unary', 'wrap_left' => '', 'wrap_right' => ''),
array ('ascii' => 'hat', 'type' => 'unary', 'wrap_left' => '', 'wrap_right' => '^'),
array ('ascii' => 'bar', 'type' => 'unary', 'wrap_left' => '', 'wrap_right' => '¯'),
array ('ascii' => 'ul', 'type' => 'unary', 'wrap_left' => '', 'wrap_right' => '_'),
array ('ascii' => 'vec', 'type' => 'unary', 'wrap_left' => '', 'wrap_right' => '→'),
array ('ascii' => 'dot', 'type' => 'unary', 'wrap_left' => '', 'wrap_right' => '.'),
array ('ascii' => 'ddot', 'type' => 'unary', 'wrap_left' => '', 'wrap_right' => '..'),
array ('ascii' => 'root', 'type' => 'binary', 'wrap_left' => '', 'wrap_right' => ''),
array ('ascii' => 'stackrel', 'type' => 'binary', 'wrap_left' => '', 'wrap_right' => ''),
// Mathvariant operators
array ('ascii' => 'bb', 'type' => 'unary', 'wrap_left' => '', 'wrap_right' => ''),
array ('ascii' => 'bbb', 'type' => 'unary', 'wrap_left' => '', 'wrap_right' => ''),
array ('ascii' => 'cc', 'type' => 'unary', 'wrap_left' => '', 'wrap_right' => ''),
array ('ascii' => 'fr', 'type' => 'unary', 'wrap_left' => '', 'wrap_right' => ''),
array ('ascii' => 'tt', 'type' => 'unary', 'wrap_left' => '', 'wrap_right' => ''),
array ('ascii' => 'sf', 'type' => 'unary', 'wrap_left' => '', 'wrap_right' => ''),
// Magnum operators
array ('ascii' => 'sum', 'ml' => '∑', 'type' => 'magnum', 'underover' => true),
array ('ascii' => 'prod', 'ml' => '∏', 'type' => 'magnum', 'underover' => true),
array ('ascii' => '^^^', 'ml' => '⋀', 'type' => 'magnum', 'underover' => true),
array ('ascii' => 'vvv', 'ml' => '⋁', 'type' => 'magnum', 'underover' => true),
array ('ascii' => 'nnn', 'ml' => '⋂', 'type' => 'magnum', 'underover' => true),
array ('ascii' => 'uuu', 'ml' => '⋃', 'type' => 'magnum', 'underover' => true),
array ('ascii' => 'int', 'ml' => '∫', 'type' => 'magnum'),
array ('ascii' => 'oint', 'ml' => '∮', 'type' => 'magnum'),
array ('ascii' => 'ointoint', 'ml' => '∯', 'type' => 'magnum'), # MortenB's idea
// Standard functions
array ('ascii' => 'sin', 'ml' => 'sin', 'type' => 'func'),
array ('ascii' => 'cos', 'ml' => 'cos', 'type' => 'func'),
array ('ascii' => 'tan', 'ml' => 'tan', 'type' => 'func'),
array ('ascii' => 'arcsin', 'ml' => 'arcsin', 'type' => 'func'),
array ('ascii' => 'arccos', 'ml' => 'arccos', 'type' => 'func'),
array ('ascii' => 'arctan', 'ml' => 'arctan', 'type' => 'func'),
array ('ascii' => 'sinh', 'ml' => 'sinh', 'type' => 'func'),
array ('ascii' => 'cosh', 'ml' => 'cosh', 'type' => 'func'),
array ('ascii' => 'tanh', 'ml' => 'tanh', 'type' => 'func'),
array ('ascii' => 'cot', 'ml' => 'cot', 'type' => 'func'),
array ('ascii' => 'sec', 'ml' => 'sec', 'type' => 'func'),
array ('ascii' => 'csc', 'ml' => 'csc', 'type' => 'func'),
array ('ascii' => 'coth', 'ml' => 'coth', 'type' => 'func'),
array ('ascii' => 'sech', 'ml' => 'sech', 'type' => 'func'),
array ('ascii' => 'csch', 'ml' => 'csch', 'type' => 'func'),
array ('ascii' => 'exp', 'ml' => 'exp', 'type' => 'func'),
array ('ascii' => 'log', 'ml' => 'log', 'type' => 'func'),
array ('ascii' => 'ln', 'ml' => 'ln', 'type' => 'func'),
array ('ascii' => 'det', 'ml' => 'det', 'type' => 'func'),
array ('ascii' => 'dim', 'ml' => 'dim', 'type' => 'func'),
array ('ascii' => 'mod', 'ml' => 'mod', 'type' => 'func'),
array ('ascii' => 'min', 'ml' => 'min', 'type' => 'func', 'underover' => true),
array ('ascii' => 'max', 'ml' => 'max', 'type' => 'func', 'underover' => true),
array ('ascii' => 'lim', 'ml' => 'lim', 'type' => 'func', 'underover' => true),
// Simple symbols
array ('ascii' => '\'', 'ml' => '\''), # single quote
array ('ascii' => '!', 'ml' => '!'),
array ('ascii' => 'O/', 'ml' => '∅'),
array ('ascii' => 'del', 'ml' => '∂'),
array ('ascii' => 'grad', 'ml' => '∇'),
array ('ascii' => 'oo', 'ml' => '∞'),
array ('ascii' => 'aleph', 'ml' => 'ℵ'),
array ('ascii' => '_|_', 'ml' => '⊥'),
array ('ascii' => 'TT', 'ml' => '⊤'),
array ('ascii' => 'deg', 'ml' => '°'),
array ('ascii' => 'diamond', 'ml' => '⋄'),
array ('ascii' => 'square', 'ml' => '□'),
array ('ascii' => 'ldots', 'ml' => '…'),
array ('ascii' => '...', 'ml' => '…'),
array ('ascii' => 'cdots', 'ml' => '⋯'),
array ('ascii' => 'vdots', 'ml' => '⋮'),
array ('ascii' => 'ddots', 'ml' => '⋱'),
array ('ascii' => 'CC', 'ml' => 'ℂ'),
array ('ascii' => 'NN', 'ml' => 'ℕ'),
array ('ascii' => 'QQ', 'ml' => 'ℚ'),
array ('ascii' => 'RR', 'ml' => 'ℝ'),
array ('ascii' => 'ZZ', 'ml' => 'ℤ'),
array ('ascii' => '(1/4)', 'ml' => '¼'),
array ('ascii' => '¼', 'ml' => '¼'),
array ('ascii' => '(1/2)', 'ml' => '½'),
array ('ascii' => '½', 'ml' => '½'),
array ('ascii' => '(3/4)', 'ml' => '¾'),
array ('ascii' => '¾', 'ml' => '¾'),
array ('ascii' => 'dx', 'ml' => 'dx'), # denne form fremtvinger italics, og nbsp pynter
array ('ascii' => 'dy', 'ml' => 'dy'),
array ('ascii' => 'dz', 'ml' => 'dz'),
array ('ascii' => 'dt', 'ml' => 'dt'),
// Greek letters
array ('ascii' => 'Alpha', 'ml' => 'Α'),
array ('ascii' => 'Beta', 'ml' => 'Β'),
array ('ascii' => 'Gamma', 'ml' => 'Γ'),
array ('ascii' => 'Delta', 'ml' => '∆'), # NB!
array ('ascii' => 'Epsilon', 'ml' => 'Ε'),
array ('ascii' => 'Zeta', 'ml' => 'Ζ'),
array ('ascii' => 'Eta', 'ml' => 'Η'),
array ('ascii' => 'Theta', 'ml' => 'Θ'),
array ('ascii' => 'Iota', 'ml' => 'Ι'),
array ('ascii' => 'Kappa', 'ml' => 'Κ'),
array ('ascii' => 'Lambda', 'ml' => 'Λ'),
array ('ascii' => 'Mu', 'ml' => 'Μ'),
array ('ascii' => 'Nu', 'ml' => 'Ν'),
array ('ascii' => 'Xi', 'ml' => 'Ξ'),
array ('ascii' => 'Omicron', 'ml' => 'Ο'),
array ('ascii' => 'Pi', 'ml' => 'Π'),
array ('ascii' => 'Rho', 'ml' => 'Ρ'),
array ('ascii' => 'Sigma', 'ml' => 'Σ'),
array ('ascii' => 'Tau', 'ml' => 'Τ'),
array ('ascii' => 'Upsilon', 'ml' => 'Υ'),
array ('ascii' => 'Phi', 'ml' => 'Φ'),
array ('ascii' => 'Chi', 'ml' => 'Χ'),
array ('ascii' => 'Psi', 'ml' => 'Ψ'),
array ('ascii' => 'Omega', 'ml' => 'Ω'),
array ('ascii' => 'alpha', 'ml' => 'α'),
array ('ascii' => 'beta', 'ml' => 'β'),
array ('ascii' => 'gamma', 'ml' => 'γ'),
array ('ascii' => 'delta', 'ml' => 'δ'),
array ('ascii' => 'epsilon', 'ml' => 'ε'),
array ('ascii' => 'zeta', 'ml' => 'ζ'),
array ('ascii' => 'eta', 'ml' => 'η'),
array ('ascii' => 'theta', 'ml' => 'θ'),
array ('ascii' => 'iota', 'ml' => 'ι'),
array ('ascii' => 'kappa', 'ml' => 'κ'),
array ('ascii' => 'lambda', 'ml' => 'λ'),
array ('ascii' => 'mu', 'ml' => 'μ'),
array ('ascii' => 'nu', 'ml' => 'ν'),
array ('ascii' => 'xi', 'ml' => 'ξ'),
array ('ascii' => 'omicron', 'ml' => 'ο'),
array ('ascii' => 'pi', 'ml' => 'π'),
array ('ascii' => 'rho', 'ml' => 'ρ'),
array ('ascii' => 'sigma', 'ml' => 'σ'),
array ('ascii' => 'sigmaf', 'ml' => 'ς'),
array ('ascii' => 'tau', 'ml' => 'τ'),
array ('ascii' => 'upsilon', 'ml' => 'υ'),
array ('ascii' => 'phi', 'ml' => 'φ'),
array ('ascii' => 'chi', 'ml' => 'χ'),
array ('ascii' => 'psi', 'ml' => 'ψ'),
array ('ascii' => 'omega', 'ml' => 'ω'),
array ('ascii' => 'thetasym', 'ml' => 'ϑ')
);
# Sortér så de største ascii-values står forrest, og dermed parses først
usort ($this->syms, function($a, $b) { return (strlen($b['ascii']) - strlen($a['ascii'])); });
# Udfyld tomme felter
for($t = 0; $t < count($this->syms); $t++) { $this->syms[$t]['ml_nobr'] = $this->syms[$t]['ml']; }
}
function parse($prevsym, $situation) {
# $situation er ass. array med følgende mulige boolean keys:
# 'master' er true for den første parse() der kaldes af handle()
# 'in_row' er true når parse() kaldes af parantes-subrutinen, dvs når parse() ikke kaldes for at indhente at argument til en operator
# 'first_in_row' er true ved første kald i ovennævnte situation, dvs første symbol i parantesen
# 'found_pipe' er true når parse() kaldes af parantes-subrutine der leder efter højre-pendant til left-pipe
# Uddrag et token $sym af $this->parsestr
if (! $situation['master']) {
$this->parsestr = ltrim($this->parsestr); # Fjern indledende whitespaces
#error_log ('PARSE: ' . $this->parsestr);
$sym = null;
if ($this->parsestr != '') {
# Test mod symboler i $this->syms, de længste først
foreach ($this->syms as $s) {
if (strpos($this->parsestr, $s['ascii']) === 0) {
$this->parsestr = substr($this->parsestr, strlen($s['ascii']));
$sym = $s;
break;
}
}
# Tal (0-9 og punktum)
if ((! isset($sym)) and (preg_match ('/^[0-9.]+/', $this->parsestr, $m))) {
$ml = $ml_nobr = ''.$m[0].'';
$sym = compact('ml', 'ml_nobr');
$this->parsestr = substr($this->parsestr, strlen($m[0]));
}
# Tekst i gåseøjne
if ((! isset($sym)) and (preg_match ('/^"(.*?)"/', $this->parsestr, $m))) {
$ml = $ml_nobr = ''.$m[1].'';
$sym = compact('ml', 'ml_nobr');
$this->parsestr = substr($this->parsestr, strlen($m[0]));
}
# Ingen symboler matcher, så udtag første tegn
if (! isset($sym)) {
$ml = $ml_nobr = ''.substr($this->parsestr, 0, 1).'';
$sym = compact('ml', 'ml_nobr');
$this->parsestr = substr($this->parsestr, 1);
}
} else {
$ml = $ml_nobr = '';
$sym = compact('ml', 'ml_nobr');
}
#error_log ('SYM: ' . $sym['ascii'] . ' -> ' . $sym['ml']);
}
# Paranteser
# Kalder parse() gentagne gange rekursivt for at lægge symboler ved siden af hinanden indtil right-bracket findes eller parsestr løber tør.
# Når parse-resultatet har 'from' sat, er der fundet en infix-operator, hvorfor sidstkomne element (arg1) er forældet og skal erstattes (arg1-infix-arg2).
# Derfor må jongleres med to variable ($old og $new) - for at sikre, at der først føjes til stakken når der ikke kommer korrektion tilbage.
# Om matrix-logik:
# Et udtryk som `((a,b),(c,d))` skal danne en matrix med a og b øverst, c og d nederst.
# Når parse() tager den første indre parantes fyldes $row med to elementer: 'a' og 'b'. Denne array returneres sammen med mathml for parantesen "(a,b)" til den kaldende parse().
# Når parse() tager den yderste parantes fyldes $row med '(a,b)' og '(c,d)', men dette er uvigtigt og bruges ikke.
# Derimod genkendes en matrix fordi hvert komma-adskilt element har sin egen ['row'] med samme antal elementer (2). Mathml-koden for disse samles i $matrix.
if (($situation['master']) or ($sym['type'] == 'leftbracket') or (($sym['ascii'] == '|') and (! $situation['found_pipe']))) {
$new = null; $old = $sym; $leftbracket = ($situation['master'] ? null : $sym); $rightbracket = null; $row = array(); $matrix = ''; $field = ''; $fields_in_row = 0;
while (true) {
$new = $this->parse($new, array('in_row' => true, 'first_in_row' => ($new === null), 'found_pipe' => ($leftbracket['ascii'] == '|')));
if (! isset($new['from'])) {
# Føj til stakken, ellers vent til næste iteration (hvor $new bliver til $old)
$ml .= $old['ml'];
if (($old['type'] != 'leftbracket') and ($old['ascii'] != '|')) {
# Det fundne er hverken start- eller slutparantes (the meat of the bracket)
$ml_nobr .= $old['ml'];
if ($old['ascii'] == ',') {
if ($field == '') $matrix = false;
$row[] = $field;
$field = '';
} else {
$field .= $old['ml'];
if (($matrix !== false) and (isset($old['row'])) and (($fields_in_row == 0) or ($fields_in_row == count($old['row'])))) {
# Gyldig matrix kræver at hver row har samme antal fields
$fields_in_row = count($old['row']); # at den er 0 går kun een gang
$matrix .= '' . implode('', $old['row']) . '';
#error_log ('ADDS TO MATRIX: ' . $fields_in_row . ' ' . implode('', $old['row']) . '');
} else {
$matrix = false;
}
}
}
}
$old = $new;
if ((($old['type'] == 'rightbracket') or ($old['ascii'] == '|')) and (! $situation['master'])) { $rightbracket = $old; break; } # right bracket found
if ($old['ml'] == '') { $matrix = false; break; } # parsestr løber tør uden right bracket
}
# Afsporet af pipe, der ikke står som parantes begynd? I så fald push rightbracket tilbage på parsestr og abortér. Den skal parres på niveauet bagude.
if (($leftbracket['ascii'] == '|') and ($rightbracket['ascii'] != '|')) {
$this->parsestr = $rightbracket['ascii'] . $this->parsestr;
$ml = $ml_nobr = $leftbracket['ml_op'] . $ml_nobr;
return compact('ml', 'ml_nobr');
}
# Tilføj sidste field (før slutparantesen) til $row
if ($field == '') $matrix = false; $row[] = $field; $field = '';
# Ved gyldig matrix erstattes alt med denne.
# Kræver: Mindst 2 columns, ellers vil `f^((x))(t)` også tælle som matrix.
if (($matrix !== false) and (count($row) > 1)) {
$ml_nobr = '' . $matrix . '';
}
# Returner string med og uden paranteser
$ml = '' . $leftbracket['ml'] . $ml_nobr . $rightbracket['ml'] . '';
if (($leftbracket['ascii'] == '(') and ($rightbracket['ascii'] == ')')) {
$ml_nobr = '' . $ml_nobr . '';
} else {
$ml_nobr = $ml;
}
#error_log ('PARANTES: (row: ' . count($row) . ') ' . $ml);
return compact ('ml', 'ml_nobr', 'row');
}
# Unære operatorer
if ($sym['type'] == 'unary') {
$new = $this->parse($sym, null);
$ml = $ml_nobr = $sym['wrap_left'] . $new['ml_nobr'] . $sym['wrap_right'];
return compact ('ml', 'ml_nobr');
}
# Binære operatorer (uden infix, dvs kun root og stackrel)
if ($sym['type'] == 'binary') {
$new1 = $this->parse($sym, null);
$new2 = $this->parse($new1, null);
$ml = $ml_nobr = $sym['wrap_left'] . $new2['ml_nobr'] . $new1['ml_nobr'] . $sym['wrap_right'];
return compact ('ml', 'ml_nobr');
}
# Standardfunktioner (som sin og cos, binder stærkt)
if ($sym['type'] == 'func') {
$old = $sym;
$new = $this->parse($sym, null);
while (isset ($new['from'])) { # fang sub- og superscripts til funktioner før selve argumentet
$old = $new;
$new = $this->parse($new, null);
}
$ml = $ml_nobr = '' . $old['ml'] . $new['ml'] . '';
#error_log ('FUNKTION: ' . $ml);
return compact ('ml', 'ml_nobr');
}
# Infix-operatorer
if ($sym['type'] == 'infix') {
if ($situation['first_in_row']) {
# Ydertilfælde som `^x` og `_y`. Skal bare reddes.
$ml = $ml_nobr = $sym['ml'];
return compact ('ml', 'ml_nobr');
}
# Den simple stak er $prevsym, $sym og $new, svarende til de tre tegn i `y_z`.
# Den udvidede stak er:
$pos1 = $prevsym['from'][0]; # `x `
$pos2 = $prevsym['from'][1]; # ` ^ `
$pos3 = $prevsym['from'][2]; # ` y `
$pos4 = $sym; # ` _ `
$pos5 = $new = $this->parse($sym, null); # ` z`
$op = $sym['ascii'];
$bundtype = isset($prevsym['bundtype']) ? $prevsym['bundtype'] : $prevsym['type']; # fx 'magnum' (går i arv)
if ((($op == '_') or ($op == '^')) and (($pos2['ascii'] == '/') or ($pos2['ascii'] == '//'))) {
# Tilfældet `x/y_z` eller `x/y^z`
$ml = $pos2['wrap_left'] . $pos1['ml_nobr'] . $pos4['wrap_left'] . $pos3['ml'] . $pos5['ml_nobr'] . $pos4['wrap_right'] . $pos2['wrap_right'];
} elseif (($op == '^') and ($pos2['ascii'] == '_') and ($pos1['underover'])) {
# Tilfældet `prod_y^z`
$ml = '' . $pos1['ml'] . $pos3['ml_nobr'] . $pos5['ml_nobr'] . '';
} elseif (($op == '_') and ($pos2['ascii'] == '^') and ($pos1['underover'])) {
# Tilfældet `prod^y_z`
$ml = '' . $pos1['ml'] . $pos5['ml_nobr'] . $pos3['ml_nobr'] . '';
} elseif (($op == '_') and ($prevsym['underover'])) {
# Tilfældet `prod_z`
$ml = '' . $prevsym['ml'] . $new['ml_nobr'] . '';
} elseif (($op == '^') and ($prevsym['underover'])) {
# Tilfældet `prod^z`
$ml = '' . $prevsym['ml'] . $new['ml_nobr'] . '';
} elseif (($op == '^') and ($pos2['ascii'] == '_')) {
# Tilfældet `x_y^z` (eneste som asciimathml.js genkender)
$ml = '' . $pos1['ml'] . $pos3['ml_nobr'] . $pos5['ml_nobr'] . '';
} elseif (($op == '_') and ($pos2['ascii'] == '^')) {
# Tilfældet `x^y_z` (kommer ud på det samme)
$ml = '' . $pos1['ml'] . $pos5['ml_nobr'] . $pos3['ml_nobr'] . '';
} elseif (($op == '_') or ($op == '^')) {
# Tilfældet `y_z` eller `y^z`
$ml = $sym['wrap_left'] . $prevsym['ml'] . $new['ml_nobr'] . $sym['wrap_right'];
} elseif (($op == '/') or ($op == '//')) {
$ml = $sym['wrap_left'] . $prevsym['ml_nobr'] . $new['ml_nobr'] . $sym['wrap_right'];
} else msg ('Dunno how I got here!');
$from = array($prevsym, $sym, $new);
$ml_nobr = $ml;
return compact ('ml', 'ml_nobr', 'from', 'bundtype');
}
# Signs (minus og plusminus)
if ($sym['type'] == 'sign') {
if (($situation['first_in_row']) or (! $situation['in_row']) or ($prevsym['type'] == 'op') or ($prevsym['bundtype'] == 'magnum')) {
# Brug fortegnsversionen af symbolet i tilfælde hvor 1) symbolet optræder allerførst i parantes/globalt, 2) symbolet optræder som argument til operator (!in_row),
# 3) symbolet optræder efter simpel inline-operator, eller 4) efter infix-symbolkæde med bundtype magnum (dvs i praksis magnum-operator med index)
$new = $this->parse($sym, null);
$ml = $ml_nobr = '' . $sym['ml_sign'] . $new['ml'] . '';
if ($new['ml'] != '') return compact ('ml', 'ml_nobr');
}
return $sym;
}
# Løsslupne right brackets - puttes tilbage til næste parserunde, mens denne returnerer tom streng (fx `(4/)_x`)
if (($sym['type'] == 'rightbracket') and (! $situation['in_row'])) {
#error_log ('LOES!');
$this->parsestr = $sym['ascii'] . $this->parsestr;
$ml = $ml_nobr = '';
return compact ('ml', 'ml_nobr');
}
# Andre symboler
return ($sym);
}
function handle($match, $state, $pos, &$handler){
if (count($this->syms) == 0) $this->setup_syms();
$this->parsestr = substr ($match, 1, -1);
if (substr ($match, 1, 1) == ' ') { $displaystyle = 'true'; } else { $displaystyle = 'false'; }
#error_log ('------ HANDLE -------');
$parsed = $this->parse(null, array('master' => true));
$return = '';
$return = '' . $return . ''; // wrappes i span aht mdblclick
return $return;
}
function render($mode, &$renderer, $data) {
if ($mode!='xhtml') return false;
$renderer->doc .= $data;
return true;
}
}
?>