Class: Pikuri::Tool::Calculator::Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/pikuri/tool/calculator.rb

Overview

Recursive-descent parser-evaluator for Python's arithmetic grammar:

additive       := multiplicative (('+' | '-') multiplicative)*
multiplicative := unary (('*' | '/' | '//' | '%') unary)*
unary          := ('+' | '-') unary | power
power          := atom ('**' unary)?
atom           := NUMBER | '(' additive ')'

The +power+→+unary+ recursion on the right operand makes ** right-associative (+232+ is 512) and lets a sign follow it (+2**-3+); unary above power on the left makes -2**2 evaluate to -4 — both as Python parses them.

Semantics follow Python 3 where Ruby differs: / is always true (float) division, // floors, 2**-1 is Float 0.5 (not a Rational), and a negative base under a fractional exponent is rejected (not a Complex).

Constant Summary collapse

TOKEN_RE =

One number or operator. +**+/+//+ listed before their single-char prefixes so the two-char operators win; number literals cover 42, 4.2, 5., .5, and e-notation. \G anchors each match at the scan position so nothing between tokens is missed.

%r{\G\s*(\*\*|//|\d+(?:\.\d*)?(?:[eE][+-]?\d+)?|\.\d+(?:[eE][+-]?\d+)?|[-+*/%()])}

Instance Method Summary collapse

Constructor Details

#initialize(expression) ⇒ Parser

Returns a new instance of Parser.

Parameters:

  • expression (String)

    raw expression as the model wrote it

Raises:

  • (Error)

    when expression contains a character no token matches



77
78
79
80
# File 'lib/pikuri/tool/calculator.rb', line 77

def initialize(expression)
  @tokens = tokenize(expression)
  @pos = 0
end

Instance Method Details

#parseInteger, Float

Parse and evaluate the whole token stream.

Returns:

  • (Integer, Float)

    the value of the expression

Raises:

  • (Error)

    on syntax errors, division by zero, or a complex result



86
87
88
89
90
91
# File 'lib/pikuri/tool/calculator.rb', line 86

def parse
  value = additive
  raise Error, "unexpected #{peek.inspect} after expression" if peek

  value
end