...
else {
if ($text!="...")
rr($im, UNIT, 0, $w-UNIT-1, $h-1, UNIT/2, $black);
imagestring($im, FONT, 2*UNIT, ($h-imagefontheight(FONT))/2,
$text, $text!="..."?$blue:$black);
} ...
* Other fonts
* Configurable dimensions
* escape-chars and or unicode in terminals
* Adding //Regexp// beside terminal and identifiers
* using a lightweight syntaxtree instead DOM
* using some standard parsing mechanism
* support for comments & special-sequences ''? ... ?''
* http://www.cs.man.ac.uk/~pjj/bnf/ebnf.html
* replace antialias function
===== Code =====
ebnf syntax
*
* @license GPL3
* @author Vincent Tscherter
* @version 0.1
*/
if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
require_once(DOKU_PLUGIN.'syntax.php');
class syntax_plugin_ebnf extends DokuWiki_Syntax_Plugin {
function getType(){
return 'substition';
}
function getSort(){
return 999;
}
function connectTo($mode) {
$this->Lexer->addSpecialPattern('.*? ',$mode,'plugin_ebnf');
}
function handle($match, $state, $pos, &$handler){
switch ($state) {
case DOKU_LEXER_ENTER :
break;
case DOKU_LEXER_MATCHED :
break;
case DOKU_LEXER_UNMATCHED :
break;
case DOKU_LEXER_EXIT :
break;
case DOKU_LEXER_SPECIAL :
break;
}
return array($match);
}
function render($mode, &$renderer, $data) {
if($mode == 'xhtml'){
try {
$text = substr($data[0], 6, strlen($data[0])-13);
$text = preg_replace( "/[<>]+/", "", $text);
$text = preg_replace( "/[\\n\\r\\t ]+/", " ", $text);
$text = urlencode($text);
$renderer->doc .= "
"; // ptype = 'normal'
} catch (Exception $e) {
$renderer->doc .= "".htmlentities($text)."\n".$e."
";
}
return true;
}
return false;
}
}
?>
.
Vincent Tscherter, tscherter@karmin.ch, Solothurn, 2009-01-18
2009-01-18 version 0.1 first release
2009-01-02 version 0.2
- title und comment literal added
- ";" als terminator-symbol added
*/
error_reporting(E_ALL|E_STRICT);
//
define('META', 'xis/ebnf v0.2 https://www.dokuwiki.org/plugin:ebnf gpl3');
// parser
define('EBNF_OPERATOR_TOKEN', 1);
define('EBNF_LITERAL_TOKEN', 2);
define('EBNF_WHITESPACE_TOKEN', 3);
define('EBNF_IDENTIFIER_TOKEN', 4);
// rendering
define('FONT', 3);
define('UNIT', 10);
define('AW', 3);
// lexemes
$ebnf_lexemes[] = array( 'type' => EBNF_OPERATOR_TOKEN, 'expr' => '[={}()|.;[\]]' );
$ebnf_lexemes[] = array( 'type' => EBNF_LITERAL_TOKEN, 'expr' => "\"[^\"]*\"" );
$ebnf_lexemes[] = array( 'type' => EBNF_LITERAL_TOKEN, 'expr' => "'[^']*'" );
$ebnf_lexemes[] = array( 'type' => EBNF_IDENTIFIER_TOKEN, 'expr' => "[a-zA-Z0-9_-]+" );
$ebnf_lexemes[] = array( 'type' => EBNF_WHITESPACE_TOKEN, 'expr' => "\\s+" );
// input example
$input = <<saveXML();
} else {
render_node($dom->firstChild, true);
}
} catch (Exception $e) {
header('Content-Type: text/plain');
$dom = new DOMDocument();
$syntax = $dom->createElement("syntax");
$syntax->setAttribute('title', 'EBNF - Syntax Error');
$syntax->setAttribute('meta', $e->getMessage());
$dom->appendChild($syntax);
render_node($dom->firstChild, true);
}
function rr($im, $x1, $y1, $x2, $y2, $r, $black){
imageline($im, $x1+$r, $y1, $x2-$r, $y1, $black);
imageline($im, $x1+$r, $y2, $x2-$r, $y2, $black);
imageline($im, $x1, $y1+$r, $x1, $y2-$r, $black);
imageline($im, $x2, $y1+$r, $x2, $y2-$r, $black);
imagearc($im, $x1+$r, $y1+$r, 2*$r, 2*$r, 180, 270, $black);
imagearc($im, $x2-$r, $y1+$r, 2*$r, 2*$r, 270, 360, $black);
imagearc($im, $x1+$r, $y2-$r, 2*$r, 2*$r, 90, 180, $black);
imagearc($im, $x2-$r, $y2-$r, 2*$r, 2*$r, 0, 90, $black);
}
function create_image($w, $h) {
global $white, $black, $blue, $red, $green, $silver;
$im = imagecreatetruecolor($w, $h) or die("no img");
imageantialias($im, true);
$white = imagecolorallocate ($im, 255, 255, 255);
$black = imagecolorallocate ($im, 0, 0, 0);
$blue = imagecolorallocate ($im, 0, 0, 255);
$red = imagecolorallocate ($im, 255, 0, 0);
$green = imagecolorallocate ($im, 0, 200, 0);
$silver = imagecolorallocate ($im, 127, 127, 127);
imagefilledrectangle($im, 0,0,$w,$h,$white);
return $im;
}
function arrow($image, $x, $y, $lefttoright) {
global $white, $black;
if (!$lefttoright)
imagefilledpolygon($image,
array($x, $y-UNIT/3, $x-UNIT, $y, $x, $y+UNIT/3), 3, $black);
else
imagefilledpolygon($image,
array($x-UNIT, $y-UNIT/3, $x, $y, $x-UNIT, $y+UNIT/3), 3, $black);
}
function render_node($node, $lefttoright) {
global $white, $black, $blue, $red, $green, $silver;
if ($node->nodeName=='identifier' || $node->nodeName=='terminal') {
$text = $node->getAttribute('value');
$w = imagefontwidth(FONT)*(strlen($text)) + 4*UNIT;
$h = 2*UNIT;
$im = create_image($w, $h);
if ($node->nodeName!='terminal') {
imagerectangle($im, UNIT, 0, $w-UNIT-1, $h-1, $black);
imagestring($im, FONT, 2*UNIT, ($h-imagefontheight(FONT))/2, $text, $red);
} else {
if ($text!="...")
rr($im, UNIT, 0, $w-UNIT-1, $h-1, UNIT/2, $black);
imagestring($im, FONT, 2*UNIT, ($h-imagefontheight(FONT))/2,
$text, $text!="..."?$blue:$black);
}
imageline($im,0,UNIT, UNIT, UNIT, $black);
imageline($im,$w-UNIT,UNIT, $w+1, UNIT, $black);
return $im;
} else if ($node->nodeName=='option' || $node->nodeName=='loop') {
if ($node->nodeName=='loop')
$lefttoright = ! $lefttoright;
$inner = render_node($node->firstChild, $lefttoright);
$w = imagesx($inner)+6*UNIT;
$h = imagesy($inner)+2*UNIT;
$im = create_image($w, $h);
imagecopy($im, $inner, 3*UNIT, 2*UNIT, 0,0, imagesx($inner), imagesy($inner));
imageline($im,0,UNIT, $w, UNIT, $black);
arrow($im, $w/2+UNIT/2, UNIT, $node->nodeName=='loop'?!$lefttoright:$lefttoright);
arrow($im, 3*UNIT, 3*UNIT, $lefttoright);
arrow($im, $w-2*UNIT, 3*UNIT, $lefttoright);
imageline($im,UNIT,UNIT, UNIT, 3*UNIT, $black);
imageline($im,UNIT,3*UNIT, 2*UNIT, 3*UNIT, $black);
imageline($im,$w-UNIT,UNIT, $w-UNIT, 3*UNIT, $black);
imageline($im,$w-3*UNIT-1,3*UNIT, $w-UNIT, 3*UNIT, $black);
return $im;
} else if ($node->nodeName=='sequence') {
$inner = render_childs($node, $lefttoright);
if (!$lefttoright)
$inner = array_reverse($inner);
$w = count($inner)*UNIT-UNIT; $h = 0;
for ($i = 0; $inodeName=='choise') {
$inner = render_childs($node, $lefttoright);
$h = (count($inner)-1)*UNIT; $w = 0;
for ($i = 0; $inodeName=='syntax') {
$title = $node->getAttribute('title');
$meta = $node->getAttribute('meta');
$node = $node->firstChild;
$names = array();
$images = array();
while ($node!=null) {
$names[] = $node->getAttribute('name');
$im = render_node($node->firstChild, $lefttoright);
$images[] = $im;
$node = $node->nextSibling;
} $wn = 0; $wr = 0; $h = 5*UNIT;
for ($i = 0; $ifirstChild;
while ($node!=null) {
$childs[] = render_node($node, $lefttoright);
$node = $node->nextSibling;
} return $childs;
}
function ebnf_scan(&$input) {
global $ebnf_lexemes;
$i = 0; $n = strlen($input); $m = count($ebnf_lexemes); $tokens = array();
while ($i < $n) {
$j = 0;
while ($j < $m &&
preg_match("/^{$ebnf_lexemes[$j]['expr']}/", substr($input,$i), $matches)==0) $j++;
if ($j<$m) {
if ($ebnf_lexemes[$j]['type']!=EBNF_WHITESPACE_TOKEN)
$tokens[] = array('type' => $ebnf_lexemes[$j]['type'],
'value' => $matches[0], 'pos' => $i);
$i += strlen($matches[0]);
} else
throw new Exception("Invalid token at position: $i");
} return $tokens;
}
function ebnf_check_token($token, $type, $value) {
return $token['type']==$type && $token['value']==$value;
}
function ebnf_parse_syntax(&$tokens) {
$dom = new DOMDocument();
$syntax = $dom->createElement("syntax");
$syntax->setAttribute('meta', META);
$dom->appendChild($syntax);
$i = 0; $token = $tokens[$i++];
if ($token['type'] == EBNF_LITERAL_TOKEN) {
$syntax->setAttribute('title',
stripcslashes(substr($token['value'], 1, strlen($token['value'])-2 )));
$token = $tokens[$i++];
}
if (!ebnf_check_token($token, EBNF_OPERATOR_TOKEN, '{') )
throw new Exception("Syntax must start with '{': {$token['pos']}");
$token = $tokens[$i];
while ($i < count($tokens) && $token['type'] == EBNF_IDENTIFIER_TOKEN) {
$syntax->appendChild(ebnf_parse_production($dom, $tokens, $i));
if ($isetAttribute('meta',
stripcslashes(substr($token['value'], 1, strlen($token['value'])-2 )));
}
}
return $dom;
}
function ebnf_parse_production(&$dom, &$tokens, &$i) {
$token = $tokens[$i++];
if ($token['type']!=EBNF_IDENTIFIER_TOKEN)
throw new Exception("Production must start with an identifier'{': {$token['pos']}");
$production = $dom->createElement("rule");
$production->setAttribute('name', $token['value']);
$token = $tokens[$i++];
if (!ebnf_check_token($token, EBNF_OPERATOR_TOKEN, "="))
throw new Exception("Identifier must be followed by '=': {$token['pos']}");
$production->appendChild( ebnf_parse_expression($dom, $tokens, $i));
$token = $tokens[$i++];
if (!ebnf_check_token($token, EBNF_OPERATOR_TOKEN, '.')
&& !ebnf_check_token($token, EBNF_OPERATOR_TOKEN, ';'))
throw new Exception("Rule must end with '.' or ';' : {$token['pos']}");
return $production;
}
function ebnf_parse_expression(&$dom, &$tokens, &$i) {
$choise = $dom->createElement("choise");
$choise->appendChild(ebnf_parse_term($dom, $tokens, $i));
$token=$tokens[$i]; $mul = false;
while (ebnf_check_token($token, EBNF_OPERATOR_TOKEN, '|')) {
$i++;
$choise->appendChild(ebnf_parse_term($dom, $tokens, $i));
$token=$tokens[$i]; $mul = true;
} return $mul ? $choise : $choise->removeChild($choise->firstChild);
}
function ebnf_parse_term(&$dom, &$tokens, &$i) {
$sequence = $dom->createElement("sequence");
$factor = ebnf_parse_factor($dom, $tokens, $i);
$sequence->appendChild($factor);
$token=$tokens[$i]; $mul = false;
while ($token['value']!='.' && $token['value']!='=' && $token['value']!='|'
&& $token['value']!=')' && $token['value']!=']' && $token['value']!='}') {
$sequence->appendChild(ebnf_parse_factor($dom, $tokens, $i));
$token=$tokens[$i]; $mul = true;
} return $mul ? $sequence: $sequence->removeChild($sequence->firstChild);
}
function ebnf_parse_factor(&$dom, &$tokens, &$i) {
$token = $tokens[$i++];
if ($token['type']==EBNF_IDENTIFIER_TOKEN) {
$identifier = $dom->createElement("identifier");
$identifier->setAttribute('value', $token['value']);
return $identifier;
} if ($token['type']==EBNF_LITERAL_TOKEN){
$literal = $dom->createElement("terminal");
$literal->setAttribute('value', stripcslashes(substr($token['value'], 1, strlen($token['value'])-2 )));
return $literal;
} if (ebnf_check_token($token, EBNF_OPERATOR_TOKEN, '(')) {
$expression = ebnf_parse_expression($dom, $tokens, $i);
$token = $tokens[$i++];
if (!ebnf_check_token($token, EBNF_OPERATOR_TOKEN, ')'))
throw new Exception("Group must end with ')': {$token['pos']}");
return $expression;
} if (ebnf_check_token($token, EBNF_OPERATOR_TOKEN, '[')) {
$option = $dom->createElement("option");
$option->appendChild(ebnf_parse_expression($dom, $tokens, $i));
$token = $tokens[$i++];
if (!ebnf_check_token($token, EBNF_OPERATOR_TOKEN, ']'))
throw new Exception("Option must end with ']': {$token['pos']}");
return $option;
} if (ebnf_check_token($token, EBNF_OPERATOR_TOKEN, '{')) {
$loop = $dom->createElement("loop");
$loop->appendChild(ebnf_parse_expression($dom, $tokens, $i));
$token = $tokens[$i++];
if (!ebnf_check_token($token, EBNF_OPERATOR_TOKEN, '}'))
throw new Exception("Loop must end with '}': {$token['pos']}");
return $loop;
}
throw new Exception("Factor expected: {$token['pos']}");
}
?>