Sha256: fd9618cb821ea7f370fa19b086bcb823c11b422dd6c7caae10219d6c895376fe

Contents?: true

Size: 1.66 KB

Versions: 2

Compression:

Stored size: 1.66 KB

Contents

require 'citrus'

# A grammar for mathematical formulas that apply the basic four operations to
# non-negative numbers (integers and floats), respecting operator precedence and
# ignoring whitespace.
module Calc
  include Citrus::Grammar

  rule :term do
    any(:additive, :factor)
  end

  rule :additive do
    all(:factor, label(:additive_op, :operator), :term) {
      def value
        operator.apply(factor.value, term.value)
      end
    }
  end

  rule :factor do
    any(:multiplicative, :primary)
  end

  rule :multiplicative do
    all(:primary, label(:multiplicative_op, :operator), :factor) {
      def value
        operator.apply(primary.value, factor.value)
      end
    }
  end

  rule :primary do
    any(:term_paren, :number)
  end

  rule :term_paren do
    all(:lparen, :term, :rparen) {
      def value
        term.value
      end
    }
  end

  rule :additive_op do
    any(:plus, :minus) {
      def apply(factor, term)
        text.strip == '+' ? factor + term : factor - term
      end
    }
  end

  rule :multiplicative_op do
    any(:star, :slash) {
      def apply(primary, factor)
        text.strip == '*' ? primary * factor : primary / factor
      end
    }
  end

  rule :number do
    any(:float, :integer)
  end

  rule :float do
    all(/[0-9]+/, '.', /[0-9]+/, :space) {
      def value
        text.strip.to_f
      end
    }
  end

  rule :integer do
    all(/[0-9]+/, :space) {
      def value
        text.strip.to_i
      end
    }
  end

  rule :lparen, ['(', :space]
  rule :rparen, [')', :space]
  rule :plus,   ['+', :space]
  rule :minus,  ['-', :space]
  rule :star,   ['*', :space]
  rule :slash,  ['/', :space]

  rule :space,  /[ \t\n\r]*/
end

Version data entries

2 entries across 2 versions & 1 rubygems

Version Path
citrus-1.4.0 examples/calc.rb
citrus-1.3.0 examples/calc.rb