Allow arbitrary whitespace between tokens [parsimonious]

Normally I wouldn't use such a short variable name as "ws", but I have
my reasons:
    a) whitespace is a common, simple thing that doesn't impose much
        cognitive overhead.
    b) sprinkling the word "whitespace" throughout the other rules makes
        them unpleasantly long.

Note that although the tests don't call it out, this resolves a minor
ambiguity in the language: previously you could have funky-looking
expressions like "5+-2". The parser knew what this meant--"add five to
negative two"--but it looked weird. Now that you can put spaces it's
much clearer what's meant by "5 + -2".
Add a `d` operator that rolls n dice of size x [parsimonious]

This doesn't illustrate a lot about parsers, but die-rollers are fun,
and of course it shows that functions in your defined language needn't
have a 1-1 mapping to functions in your host language.
Dead-simple grammar that can read natural numbers [ply]

PLY's design might not be at all obvious to you. Here's what's going on:
In Python, if the first statement in a function is a void string
declaration, that string is a "docstring," and is assigned to that
function's __doc__ attribute (see PEP-257). PLY introspects the module
in which it is invoked, looks for functions named t_foo (for tokenizing)
and p_foo (for parsing), and then inspects their __doc__ attributes to
extract rules from them.

It additionally looks for a variable called `tokens`, which provides it
with a starting point for finding the _foo functions.

In parser methods (p_foo), the `p` argument is an arrayish with one
element per element in the defined rule. So in our p_number function, p
consists of ['number', x] where x is the result of t_NUMBER.

Beyond the PLY wackiness, there isn't a lot to see here. Our very
primitive parser can take strings containing numbers and return their
numeric representation.
Parse decimal numbers [ply]

Numbers are now a series of digits, possibly with a . in the middle of
them. This parser doesn't accept inputs like "15." or ".15", which are
arguably valid input. Personally I figure it won't kill the user to type
a 0 once in a while.
Shut up, ply [ply]

PLY complains about having no t_error function defined. We don't need a
custom t_error; the LexErrors thrown by PLY are sufficient for our
purposes. I'm not sure why this is worth a warning, but it's annoying in
the tests.
Add support for negative numbers [ply]

This is a fairly simple change building on the two we already did:
numbers can now have an optional - in front of them, indicating
negation. So far, the extensions we've made to our grammar rules haven't
required any changes in the Calculator--they're all reflected in
Python's `float` method.
Now the parser can add numbers together [ply]

This is not quite the design recommended by the ply documentation, but I
think it's a nice clean design. The tokenizer returns the values
associated with each token, and the parser consumes those values. In
this case, the value associated with '+' happens to be a function of two
numbers, so that's what we'll return.

If you've already read the parsimonious version of this parser, you'll
notice that PLY allows `expression: expression plus expression` whereas
parsimonious would've gone into an infinite loop on that grammar. This
is a distinction between the LALR grammars used by PLY and the PEG
grammars used by parsimonious.

Note that this uncovered a bug in my decimal-numbers regex. Oops! I
blame PLY for being so regex-oriented. It's definitely not my fault for
making a classic regex mistake. Nope.
Add various operators [ply]

Now you can see what I meant about a nice clean design from returning
functions in the tokenizer. Each operator token returns the associated
function, and the parser just calls it. In a more classic yacc
implementation, the operator tokens would just return their string
representations, and you'd have a big if-elsif-elsif-elsif block where
you look up the behavior associated with the strings.

You may notice that the number rule changed here. Previously a unary '-'
was considered part of the numeric token, whereas now it's a separate
operator. It turns out that with two different ways to interpret the '-'
token, you end up with an ambiguous grammar and the behavior is
unpredictable. Having the unary '-' pass an explicit 0 to the binary
subtraction function is either an elegant workaround or a kludgy hack,
depending on your viewpoint.
Add parentheticals to the language [ply]

The grammar here is pretty straightforward; an expression can now be an
otherwise-valid expression surrounded by parentheses.

You'll notice that we had to hack in parse-error expressions. By
default, PLY prints parse errors to STDOUT and returns None. That's not
very useful in any context I can think of. Instead, we inject a logger
that blackholes all input except calls to error(); calls to error()
raise a ParseError. It's pretty kludgey, but as the tests show, it at
least works.
Allow arbitrary whitespace in our language [ply]

PLY looks for a t_ignore rule; characters in this rule will be skipped
over during lexing. Note that unlike the other rules, t_ignore is a list
of characters, not a regex; simply replacing our ' \t' rule with r'\s'
would not work.
Dead-simple grammar that can read natural numbers [parsley]

Our grammar has a single rule, "number." The syntax here is a little
more than just a grammar: Parsley supplies a few operators that make it
easier to build a parser and grammar in one go. the angle brackets in
`<digit+>` mean that the `digit+` rule returns a single string
containing all the digits it matched, rather than a list. The `:ds`
assigns that matched group to a locally-available variable called `ds`.
Finally, everything after the `->` is python code, the return value of
which will be the ultimate return value of the rule.

Tying it all together, `<digit+>:ds -> int(ds)` matches one or more
numerals and casts them to a Python int.

(note that the `digit` rule is supplied out-of-the-box by Parsley)
Add support for decimal numbers [parsley]

Numbers are now a series of digits, possibly followed by a dot and a
second series of digits. We also had to switch from using int() to
float() to correctly support these numbers!
Add support for negative numbers [parsley]

Numbers may now have an optional leading `-`. Notice that since we're
eventually delegating to Python's float() method, the hard work of
actually parsing the number is handled for us. We just need to make sure
our rule can match the user input, and after that it's gravy.
Now our parser can add two numbers [parsley]

Notice that the `+` rule returns a function. This seems a little
overcomplicated now, but when we start adding operators you'll see that
it provides a certain elegance.

Notice also that we had to change the function called by calculate().
The Parsley function makeGrammar returns a function that takes a piece
of text and returns a parser; that parser has functions with names
corresponding to the rules defined in the grammar. Since our grammar's
outermost rule is now expression, that's the function we should call.
Allow chaining additions [parsley]

Notice that our addition rule requires a number on the left side. This
is one of the cases where we do care about the class of grammar
generated by our parser-generator. Specifically, Parsley generates a PEG
grammar, which means that it breaks if you define a self-recursive rule.
If our `addition` rule were `expression plus expression`, the left-side
`expression` term would refer back to `addition`, creating a
non-terminating situation.
Add various operators [parsley]

Now you can see the elegance of having our operator rules return
functions: the `operation` rule simply needs to apply the returned
function to its left- and right-hand arguments, leaving the
symbol-to-operation logic to the operator rules.

The `roll` function is fairly compactly-written, but if you read it
carefully you should be able to see what it does: generate `num` random
integers between 1 and `size`, then add them all up.

This commit finally reveals the import of that dict we've been passing
to makeGrammar: it is a mapping of names to values that will be
available inside our grammar.
Add parentheticals to our language [parsley]

The `parenthetical` rule allows us to potentially have an expression to
the left of an operator, but unlike `expression operator expression` it
doesn't actually create an endless loop, because the '(' literal means
it can only occur in a bounded set of circumstances.
Allow arbitrary whitespace in our language [parsley]

As shown in the tests, this resolves a minor ambiguity in our language:
previously if you wrote `5+-2` it wasn't clear what was going on. Now
that you can write `5 + -2` it's a bit clearer.