Skip to content

Instantly share code, notes, and snippets.

@ShayCichocki
Created October 24, 2017 01:06
Show Gist options
  • Save ShayCichocki/5c41f357425dd1dd364f38020b5f552d to your computer and use it in GitHub Desktop.
Save ShayCichocki/5c41f357425dd1dd364f38020b5f552d to your computer and use it in GitHub Desktop.
BNF form parser, exampled with story generating bnf
<?php
class BNFParserGenerator {
private $defs = [];
/**
* This converts the BNF string into a set of generator definitions
* that we can use later
* @param string $string
*/
public function parseString(string $string) {
$string = str_replace("\\n", 'NEW_LINE', $string);
$split = array_filter(explode("\n", $string));
$exploded = array_map(function($gen) {
$gen = str_replace("NEW_LINE", "\n", $gen);
return explode("::=", trim($gen));
}, $split);
foreach ($exploded as $item) {
$matches = [];
preg_match('/<([A-z\-]+)>/', $item[0], $matches);
$generators = explode("|", $item[1]);
$generators = array_map(function($gen) {
return trim($gen);
}, $generators);
$this->defs[$matches[1]] = $generators;
}
}
/**
* This creates whole new strings based on the grammar
* @param string $startGeneratorName
* @return string
*/
public function generateString(string $startGeneratorName): string {
if(!isset($this->defs[$startGeneratorName])) {
return 'Generator Doesnt Exist';
}
//get a random key from the set of tokens that the generator can make
$key = array_rand($this->defs[$startGeneratorName]);
$phrase = $this->defs[$startGeneratorName][$key];
//regex to potentially find replaceable elements in the selected token
$re = '/(?<!\\\\)<(.*?)(?<!\\\\)>/';
//Does a callback on all regex matches and replaces them with the generator
//aka recurse recurse
$result = preg_replace_callback($re, function($match) {
return $this->generateString($match[1]);
}, $phrase);
//dont need this and could fix grammar to not have '' but pfft
$result = str_replace("'", "", $result);
return $result;
}
}
$bnfString = "
<plot> ::= <plot-point>. <plot> | <plot-point>. <transition><plot-point>.<plot> | <plot-point>.
<plot-point> ::= <char-action><necessities><character><about> | <char-action>
<char-action> ::= <character><action><about>
<necessities> ::= '-' | '->' | <about> | '+' | '*'
<action> ::= '1' | '2' | '3' | '4' |'5' | ''
<about> ::= [<character>] | [<character>+<character>] | ''
<character> ::= 'A'|'B'|'C'|'D'|'E'|'Z'
<transition> ::= '\\n=\\n' | '\\n...\\n' | ''
";
$parser = new BNFParserGenerator();
$parser->parseString($bnfString);
$result = '';
echo $parser->generateString('plot')."\n";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment