Skip to content

Commit

Permalink
Refactored calculator examples.
Browse files Browse the repository at this point in the history
Added ability to interpret unary operators.
  • Loading branch information
mjackson committed Sep 8, 2010
1 parent b0e86fb commit a63e538
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 24 deletions.
46 changes: 34 additions & 12 deletions examples/calc.citrus
@@ -1,6 +1,6 @@
# A grammar for mathematical formulas that apply the basic four operations to
# non-negative numbers (integers and floats), respecting operator precedence and
# ignoring whitespace.
# A grammar for mathematical formulas that apply basic mathematical operations
# to all numbers, respecting operator precedence and grouping of expressions
# while ignoring whitespace.
#
# An identical grammar that is written using pure Ruby can be found in calc.rb.
grammar Calc
Expand All @@ -20,13 +20,25 @@ grammar Calc
end

rule factor
multiplicative | exponent
multiplicative | prefix
end

rule multiplicative
(exponent multiplicative_operator factor) {
(prefix multiplicative_operator factor) {
def value
multiplicative_operator.apply(primary.value, factor.value)
multiplicative_operator.apply(prefix.value, factor.value)
end
}
end

rule prefix
prefixed | exponent
end

rule prefixed
(unary_operator prefix) {
def value
unary_operator.apply(prefix.value)
end
}
end
Expand Down Expand Up @@ -83,24 +95,34 @@ grammar Calc

rule additive_operator
(('+' | '-') space) {
def apply(factor, term)
factor.send(text.strip, term)
def apply(n1, n2)
n1.send(text.strip, n2)
end
}
end

rule multiplicative_operator
(('*' | '/' | '%') space) {
def apply(primary, factor)
primary.send(text.strip, factor)
def apply(n1, n2)
n1.send(text.strip, n2)
end
}
end

rule exponential_operator
('**' space) {
def apply(primary, exponent)
primary ** exponent
def apply(n1, n2)
n1 ** n2
end
}
end

rule unary_operator
(('~' | '+' | '-') space) {
def apply(n)
op = text.strip
# Unary + and - require an @.
n.send(op == '~' ? op : '%s@' % op)
end
}
end
Expand Down
46 changes: 34 additions & 12 deletions examples/calc.rb
@@ -1,8 +1,8 @@
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.
# A grammar for mathematical formulas that apply basic mathematical operations
# to all numbers, respecting operator precedence and grouping of expressions
# while ignoring whitespace.
#
# An identical grammar that is written using Citrus' own grammar syntax can be
# found in calc.citrus.
Expand All @@ -23,13 +23,25 @@ def value
end

rule :factor do
any(:multiplicative, :exponent)
any(:multiplicative, :prefix)
end

rule :multiplicative do
all(:exponent, :multiplicative_operator, :factor) {
all(:prefix, :multiplicative_operator, :factor) {
def value
multiplicative_operator.apply(primary.value, factor.value)
multiplicative_operator.apply(prefix.value, factor.value)
end
}
end

rule :prefix do
any(:prefixed, :exponent)
end

rule :prefixed do
all(:unary_operator, :prefix) {
def value
unary_operator.apply(prefix.value)
end
}
end
Expand Down Expand Up @@ -86,24 +98,34 @@ def value

rule :additive_operator do
all(any('+', '-'), :space) {
def apply(factor, term)
factor.send(text.strip, term)
def apply(n1, n2)
n1.send(text.strip, n2)
end
}
end

rule :multiplicative_operator do
all(any('*', '/', '%'), :space) {
def apply(primary, factor)
primary.send(text.strip, factor)
def apply(n1, n2)
n1.send(text.strip, n2)
end
}
end

rule :exponential_operator do
all('**', :space) {
def apply(primary, exponent)
primary ** exponent
def apply(n1, n2)
n1 ** n2
end
}
end

rule :unary_operator do
all(any('~', '+', '-'), :space) {
def apply(n)
op = text.strip
# Unary + and - require an @.
n.send(op == '~' ? op : '%s@' % op)
end
}
end
Expand Down
24 changes: 24 additions & 0 deletions test/helper.rb
Expand Up @@ -121,5 +121,29 @@ def test_exponent
def test_exponent_float
do_test('2**2.2')
end

def test_negative
do_test('-5')
end

def test_double_negative
do_test('--5')
end

def test_complement
do_test('~4')
end

def test_double_complement
do_test('~~4')
end

def test_mixed_unary
do_test('~-4')
end

def test_complex_with_negatives
do_test('4 * -7 / (8.0 + 1_2)**2')
end
end
end

0 comments on commit a63e538

Please sign in to comment.