* */ 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 = ''.$parsed['ml'].''; $return = '' . $return . ''; // wrappes i span aht mdblclick return $return; } function render($mode, &$renderer, $data) { if ($mode!='xhtml') return false; $renderer->doc .= $data; return true; } } ?>