Class: Pikuri::Tool::Calculator::Parser
- Inherits:
-
Object
- Object
- Pikuri::Tool::Calculator::Parser
- Defined in:
- lib/pikuri/tool/calculator.rb
Overview
Recursive-descent parser-evaluator for Python’s arithmetic expression grammar:
additive := multiplicative (('+' | '-') multiplicative)*
multiplicative := unary (('*' | '/' | '//' | '%') unary)*
unary := ('+' | '-') unary | power
power := atom ('**' unary)?
atom := NUMBER | '(' additive ')'
The power → unary recursion on the right operand is what makes ** right-associative (+2**3**2+ is 512) and lets a sign follow it (+2**-3+); unary sitting above power on the left is what makes -2**2 evaluate to -4 — both exactly as Python parses them.
Semantics follow Python 3 where Ruby differs: / is always true (float) division, // floors, 2**-1 is the Float 0.5 (Ruby would return a Rational), and a negative base under a fractional exponent is rejected (Ruby would return a Complex).
Constant Summary collapse
- TOKEN_RE =
One number or operator. ** /
//listed before their single-character prefixes so the two-character operators win; number literals cover42,4.2,5.,.5, and e-notation on any of them.\Ganchors each match at the scan position so nothing between tokens goes unnoticed. %r{\G\s*(\*\*|//|\d+(?:\.\d*)?(?:[eE][+-]?\d+)?|\.\d+(?:[eE][+-]?\d+)?|[-+*/%()])}
Instance Method Summary collapse
-
#initialize(expression) ⇒ Parser
constructor
A new instance of Parser.
-
#parse ⇒ Integer, Float
Parse and evaluate the whole token stream.
Constructor Details
#initialize(expression) ⇒ Parser
Returns a new instance of Parser.
93 94 95 96 |
# File 'lib/pikuri/tool/calculator.rb', line 93 def initialize(expression) @tokens = tokenize(expression) @pos = 0 end |
Instance Method Details
#parse ⇒ Integer, Float
Parse and evaluate the whole token stream.
102 103 104 105 106 107 |
# File 'lib/pikuri/tool/calculator.rb', line 102 def parse value = additive raise Error, "unexpected #{peek.inspect} after expression" if peek value end |