1Parser Library 2============== 3 4This library allows you to easily implement recursive-descent parsers. 5 6Installation 7------------ 8You can install this library through composer: 9 10.. code-block :: bash 11 12 composer require jms/parser-lib 13 14or add it to your ``composer.json`` file directly. 15 16Example 17------- 18Let's assume that you would like to write a parser for a calculator. For simplicity 19sake, we will assume that the parser would already return the result of the 20calculation. Inputs could look like this ``1 + 1`` and we would expect ``2`` as 21a result. 22 23The first step, is to create a lexer which breaks the input string up into 24individual tokens which can then be consumed by the parser. This library provides 25a convenient class for simple problems which we will use:: 26 27 $lexer = new \JMS\Parser\SimpleLexer( 28 '/ 29 # Numbers 30 ([0-9]+) 31 32 # Do not surround with () because whitespace is not meaningful for 33 # our purposes. 34 |\s+ 35 36 # Operators; we support only + and - 37 |(+)|(-) 38 /x', // The x modifier tells PCRE to ignore whitespace in the regex above. 39 40 // This maps token types to a human readable name. 41 array(0 => 'T_UNKNOWN', 1 => 'T_INT', 2 => 'T_PLUS', 3 => 'T_MINUS'), 42 43 // This function tells the lexer which type a token has. The first element is 44 // an integer from the map above, the second element the normalized value. 45 function($value) { 46 if ('+' === $value) { 47 return array(2, '+'); 48 } 49 if ('-' === $value) { 50 return array(3, '-'); 51 } 52 if (is_numeric($value)) { 53 return array(1, (integer) $value); 54 } 55 56 return array(0, $value); 57 } 58 ); 59 60Now the second step, is to create the parser which can consume the tokens once 61the lexer has split them:: 62 63 class MyParser extends \JMS\Parser\AbstractParser 64 { 65 const T_UNKNOWN = 0; 66 const T_INT = 1; 67 const T_PLUS = 2; 68 const T_MINUS = 3; 69 70 public function parseInternal() 71 { 72 $result = $this->match(self::T_INT); 73 74 while ($this->lexer->isNextAny(array(self::T_PLUS, self::T_MINUS))) { 75 if ($this->lexer->isNext(self::T_PLUS)) { 76 $this->lexer->moveNext(); 77 $result += $this->match(self::T_INT); 78 } else if ($this->lexer->isNext(self::T_MINUS)) { 79 $this->lexer->moveNext(); 80 $result -= $this->match(self::T_INT); 81 } else { 82 throw new \LogicException('Previous ifs were exhaustive.'); 83 } 84 } 85 86 return $result; 87 } 88 } 89 90 $parser = new MyParser($lexer); 91 $parser->parse('1 + 1'); // int(2) 92 $parser->parse('5 + 10 - 4'); // int(11) 93 94That's it. Now you can perform basic operations already. If you like you can now 95also replace the hard-coded integers in the lexer with the class constants of the 96parser. 97 98License 99------- 100 101The code is released under the business-friendly `Apache2 license`_. 102 103Documentation is subject to the `Attribution-NonCommercial-NoDerivs 3.0 Unported 104license`_. 105 106.. _Apache2 license: http://www.apache.org/licenses/LICENSE-2.0.html 107.. _Attribution-NonCommercial-NoDerivs 3.0 Unported license: http://creativecommons.org/licenses/by-nc-nd/3.0/ 108 109