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