19. QueryLang: Example query
parsers OR 123 AND (dpc OR phpbnl)
Query (OR)
|-- Term - "parsers"
|-- Query (AND)
|-- Term - "123"
|-- Query (OR)
|-- Term - "dpc"
|-- Term - "phpbnl"
19
20. v1/Peg/grammar.peg.inc
/*!* QueryLangV1
Term: /[wd]+/
*/
public function parse()
{
$match = $this->match_Term();
if (!$match) {
return '';
}
return $match['text'];
}
20
22. v1/Peg/grammar.peg.inc test
$parser = new Parser('test');
print_r($parser->parse());
// test
$parser = new Parser('test 123');
print_r($parser->parse());
// test
22
23. v2/Peg/grammar.peg.inc
/*!* QueryLangV2
Query: Term (> Term)*
Term: /[wd]+/
*/
public function parse()
{
$result = $this->match_Query();
return $result['query'];
}
23
24. v2/Peg/grammar.peg.inc (cont.)
public function Query__construct(&$result)
{
$result['query'] = new NodeQuery();
}
public function Query_Term(&$result, $sub)
{
$term = new NodeTerm($sub['text']);
$result['query']->addTerm($term);
}
24
25. v2/Peg/grammar.peg.inc test
$parser = new Parser('test 123');
print_r($parser->parse());
Query
|-- Term - "test"
|-- Term - "123"
25
27. v3/Peg/grammar.peg.inc (cont.)
Query: AndQuery ([ "OR" ] AndQuery)*
AndQuery: Term ([ "AND" ] Term)*
public function Query__construct(&$r) {
$r['query'] = new NodeQuery('OR');
}
public function Query_AndQuery(&$r, $s) {
$r['query']->add($s['query']);
}
public function AndQuery__construct(&$r) {
$r['query'] = new NodeQuery('AND');
}
public function AndQuery_Term(&$r, $s) {
$r['query']->add($s['query']);
27
}
28. v3/Peg/grammar.peg.inc (cont.)
/*!* QueryLangV3
Term: "(" Query ")" | Value:/[wd]+/
*/
public function Term_Query(&$r, $s){
$r['query'] = $s['query'];
}
public function Term_Value(&$r, $s){
$r['query']= new NodeTerm($s['text']);
}
28
29. v3/Peg/grammar.peg.inc test
$parser = new Parser('a AND b OR c');
Query (OR)
|-- Query (AND)
| |-- Term - "a"
| |-- Term - "b"
|-- Query (AND)
|-- Term - "c"
29
31. Optimized query
$parser = new Parser('a AND b OR c');
$query = $parser->parse();
$queryOptimizer = new Optimizer($query);
$query = $queryOptimizer->optimize();
Query (OR)
|-- Term - "c"
|-- Query (AND)
| |-- Term - "a"
| |-- Term - "b"
31
33. Manual Parser Building: Lexing
Characters get turned into tokens by a lexical
analyzer. Also called lexer, scanner or
tokenizer.
"a OR (b)"
'term' => "a"
'OR'
'LeftParen'
'term' => "b"
'RightParen' 33
34. Manual Parser Building: Lexing
if ($this->_match('LeftParen', '/^(()/')) {continue;}
if ($this->_match('RightParen', '/^())/')) {continue;}
if ($this->_match('OR', '/^(OR)/i'))
{continue;}
if ($this->_match('AND', '/^(AND)/i')) {continue;}
if ($this->_match('TermValue', '/^([wd]+)/i'))
{continue;}
if ($this->_match('WS', '/^s+/', true)) {continue;}
34
36. Manual Parser Building: Parsing
Non-terminals become methods
protected function _query();
protected function _andQuery();
protected function _term();
Parse to a tree structure.
36
44. More resources
Examples of modern parsers in PHP:
Twig (Predictive Parser)
Behats Gherkin (Predictive Parser)
Smarty 3 (LALR parser)
More information:
Rich Programmer Food by Steve Yegge
Let’s Build a Compiler, by Jack Crenshaw
nathansuniversity.com
Coursera: Compilers by Stanford University
SE-Radio: Episode 182: DSLs
44