Parser Library
==============

This library allows you to easily implement recursive-descent parsers.

Installation
------------
You can install this library through composer:

.. code-block :: bash

    composer require jms/parser-lib

or add it to your ``composer.json`` file directly.

Example
-------
Let's assume that you would like to write a parser for a calculator. For simplicity
sake, we will assume that the parser would already return the result of the
calculation. Inputs could look like this ``1 + 1`` and we would expect ``2`` as
a result.

The first step, is to create a lexer which breaks the input string up into
individual tokens which can then be consumed by the parser. This library provides
a convenient class for simple problems which we will use::

    $lexer = new \JMS\Parser\SimpleLexer(
        '/
            # Numbers
            ([0-9]+)

            # Do not surround with () because whitespace is not meaningful for
            # our purposes.
            |\s+

            # Operators; we support only + and -
            |(\+)|(-)
        /x', // The x modifier tells PCRE to ignore whitespace in the regex above.

        // This maps token types to a human readable name.
        array(0 => 'T_UNKNOWN', 1 => 'T_INT', 2 => 'T_PLUS', 3 => 'T_MINUS'),

        // This function tells the lexer which type a token has. The first element is
        // an integer from the map above, the second element the normalized value.
        function($value) {
            if ('+' === $value) {
                return array(2, '+');
            }
            if ('-' === $value) {
                return array(3, '-');
            }
            if (is_numeric($value)) {
                return array(1, (integer) $value);
            }

            return array(0, $value);
        }
    );

Now the second step, is to create the parser which can consume the tokens once
the lexer has split them::

    class MyParser extends \JMS\Parser\AbstractParser
    {
        const T_UNKNOWN = 0;
        const T_INT = 1;
        const T_PLUS = 2;
        const T_MINUS = 3;

        public function parseInternal()
        {
            $result = $this->match(self::T_INT);

            while ($this->lexer->isNextAny(array(self::T_PLUS, self::T_MINUS))) {
                if ($this->lexer->isNext(self::T_PLUS)) {
                    $this->lexer->moveNext();
                    $result += $this->match(self::T_INT);
                } else if ($this->lexer->isNext(self::T_MINUS)) {
                    $this->lexer->moveNext();
                    $result -= $this->match(self::T_INT);
                } else {
                    throw new \LogicException('Previous ifs were exhaustive.');
                }
            }

            return $result;
        }
    }

    $parser = new MyParser($lexer);
    $parser->parse('1 + 1'); // int(2)
    $parser->parse('5 + 10 - 4'); // int(11)

That's it. Now you can perform basic operations already. If you like you can now
also replace the hard-coded integers in the lexer with the class constants of the
parser.

License
-------

The code is released under the business-friendly `Apache2 license`_.

Documentation is subject to the `Attribution-NonCommercial-NoDerivs 3.0 Unported
license`_.

.. _Apache2 license: http://www.apache.org/licenses/LICENSE-2.0.html
.. _Attribution-NonCommercial-NoDerivs 3.0 Unported license: http://creativecommons.org/licenses/by-nc-nd/3.0/

