APPENDIX B ■ A SIMPLE PARSER
The idea behind this use of the Composite pattern is that a client can build up a grammar in code
that closely matches EBNF notation. Table B–1 shows the parallels between these classes and EBNF
fragments.
Table B–1. Composite Parsers and EBNF
Class EBNF Example DescriptionAlternationParse orExpr | andExpr Either one or anotherSequenceParse 'and' operand A list (all required in order)RepetitionParse ( eqExpr )* Zero or more requiredNow to build some client code to implement the mini-language. As a reminder, here is the EBNF
fragment I presented in Chapter 11:
expr ::= operand (orExpr | andExpr )
operand ::= ( '(' expr ')' |
orExpr ::= 'or' operand
andExpr ::= 'and' operand
eqExpr ::= 'equals' operand
variable ::= '$'
This simple class builds up a grammar based on this fragment and runs it:class MarkParse {
private $expression;
private $operand;
private $interpreter;
private $context;
function __construct( $statement ) {
$this->compile( $statement );
}
function evaluate( $input ) {
$icontext = new InterpreterContext();
$prefab = new VariableExpression('input', $input );
// add the input variable to Context
$prefaB–>interpret( $icontext );
$this->interpreter->interpret( $icontext );
$result = $icontext->lookup( $this->interpreter );
return $result;
}
function compile( $statement_str ) {
// build parse tree
$context = new \gi\parse\Context();
$scanner = new \gi\parse\Scanner(
new \gi\parse\StringReader($statement_str), $context );
$statement = $this->expression();