diff --git a/README.txt b/README.txt
index 154094e..5928ad7 100644
--- a/README.txt
+++ b/README.txt
@@ -114,7 +114,7 @@ puts "the result is #{result}"
Bundled with this library there is an example of an Arithmetic Evaluator,
which evaluates simple expressions like "3-7*(6-2)". In the "examples/ariteval" directory there are:
[exp.rb] contains all the Abstract Syntax Tree node definitions.
-[ariteval.rb] contains the productions definitions using LLIP::Parser.
+[ariteval.rb] contains the Ariteval class which defines all the productions using LLIP::Parser.
[evaluator.rb] a simple visitor which uses the classes defined in exp.rb.
== Author
diff --git a/Rakefile b/Rakefile
index d843ede..7e84fcf 100644
--- a/Rakefile
+++ b/Rakefile
@@ -13,7 +13,7 @@ Hoe.new('llip',LLIP::VERSION) do |p|
p.description = p.paragraphs_of('README.txt', 1..3).join("\n\n")
p.summary = "LLIP is a tool to geneate a LL(k) parser."
p.url = "http://llip.rubyforge.org"
- p.rdoc_pattern = /(^lib\/llip\/.*|.*\.txt)/
+ p.rdoc_pattern = /(^lib\/llip\/.*|.*\.txt|^examples\/ariteval\/.*)/
p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
end
diff --git a/examples/ariteval/ariteval.rb b/examples/ariteval/ariteval.rb
index cda8d77..3437336 100644
--- a/examples/ariteval/ariteval.rb
+++ b/examples/ariteval/ariteval.rb
@@ -1,108 +1,132 @@
require 'parser'
require 'evaluator'
+# It's a simple arithmetical evaluator. It's able to parse expressions like these:
+# * ( a = 3 * 2 ) - ( 24 + a ),
+# * 3 * (4 - 2) + 5*(4/2)/(3-2).
+#
+# It realizes the following grammar:
+#
+# non terminal symbols = { SCOPE, EXP, TERM, POW, FACTOR, NUMBER }
+# terminal symbols = any number, the charachters " , . + - * / ^ = [ ] ( ) ' "
+#
+# an id is an unlimited string composed of every charachter "a".."Z" and the "_"
+#
+# P = {
+# SCOPE ::= EXP
+# EXP ::= EXP + TERM
+# EXP ::= EXP - TERM
+# TERM ::= POW
+# TERM ::= TERM * FACTOR
+# TERM ::= TERM / FACTOR
+# FACTOR ::= any sequence of 0,1,2,3,4,5,6,7,8,9
+# FACTOR ::= an id
+# FACTOR ::= an id =
+# FACTOR ::= ( EXP )
+# }
+#
class Ariteval < Parser
- def initialize
- super
- @evaluator = Evaluator.new
- end
+ def initialize
+ super
+ @evaluator = Evaluator.new
+ end
- def evaluate(source)
- parse(source).accept(@evaluator)
- @evaluator.result
- end
+ def evaluate(source)
+ parse(source).accept(@evaluator)
+ @evaluator.result
+ end
- # tokens definitions
+ # tokens definitions
- numbers = ("0".."9").to_a.join("|")
- token :number, "(#{numbers})+ *"
+ numbers = ("0".."9").to_a.join("|")
+ token :number, "(#{numbers})+ *"
- token :plus, '\+ *'
+ token :plus, '\+ *'
- token :minus, '- *'
+ token :minus, '- *'
- token :mul, '\* *'
+ token :mul, '\* *'
- token :div, '/ *'
+ token :div, '/ *'
- token :"(", '\( *'
+ token "(".to_sym, '\( *'
- token :")", '\) *'
+ token ")".to_sym, '\) *'
- identifiers = (("a".."z").to_a + ("A".."Z").to_a).join("|")
- token :ident, "(#{identifiers}) *"
+ identifiers = (("a".."z").to_a + ("A".."Z").to_a).join("|")
+ token :ident, "(#{identifiers}) *"
- token :assign, "= *"
+ token :assign, "= *"
- # production definitions
+ # production definitions
- lookahead(true)
+ lookahead(true)
- scope :exp
-
- production(:exp,:recursive) do |prod|
- prod.default { |scanner,parser| parser.parse_term }
-
- prod.token(:plus) do |term_seq,scanner,parser|
- scanner.next
- next_term = parser.parse_term
- PlusExp.new(term_seq,next_term)
- end
-
- prod.token(:minus) do |term_seq,scanner,parser|
- scanner.next
- next_term = parser.parse_term
- MinusExp.new(term_seq,next_term)
- end
+ scope :exp
+
+ production(:exp,:recursive) do |prod|
+ prod.default { |scanner,parser| parser.parse_term }
+
+ prod.token(:plus) do |term_seq,scanner,parser|
+ scanner.next
+ next_term = parser.parse_term
+ PlusExp.new(term_seq,next_term)
+ end
+
+ prod.token(:minus) do |term_seq,scanner,parser|
+ scanner.next
+ next_term = parser.parse_term
+ MinusExp.new(term_seq,next_term)
+ end
- end
+ end
- production(:term,:recursive) do |prod|
- prod.default { |scanner,parser| parser.parse_factor }
+ production(:term,:recursive) do |prod|
+ prod.default { |scanner,parser| parser.parse_factor }
- prod.token(:mul) do |factor_seq,scanner,parser|
- scanner.next
- next_factor = parser.parse_factor
- MulExp.new(factor_seq,next_factor)
- end
+ prod.token(:mul) do |factor_seq,scanner,parser|
+ scanner.next
+ next_factor = parser.parse_factor
+ MulExp.new(factor_seq,next_factor)
+ end
- prod.token(:div) do |factor_seq,scanner,parser|
- scanner.next
- next_factor = parser.parse_factor
- DivExp.new(factor_seq,next_factor)
- end
- end
+ prod.token(:div) do |factor_seq,scanner,parser|
+ scanner.next
+ next_factor = parser.parse_factor
+ DivExp.new(factor_seq,next_factor)
+ end
+ end
- production(:factor,:single) do |prod|
+ production(:factor,:single) do |prod|
- prod.token(:number) do |result,scanner|
- current = scanner.current
- scanner.next
- NumExp.new(current.value.to_i)
- end
-
- prod.token(:"(") do |result,scanner,parser|
- scanner.next
- result = parser.parse_exp
- parser.raise "Every '(' must be followed by a ')'" unless scanner.current == :")"
- scanner.next
- result
- end
-
- prod.token(:ident,:assign) do |result,scanner,parser|
- name = scanner.current.to_s.strip
- scanner.next
- scanner.next
- AssignIdentExp.new(name,parser.parse_exp)
- end
-
- prod.token(:ident) do |result,scanner,parser|
- result = IdentExp.new(scanner.current.to_s.strip)
- scanner.next
- result
- end
-
- end
+ prod.token(:number) do |result,scanner|
+ current = scanner.current
+ scanner.next
+ NumExp.new(current.value.to_i)
+ end
+
+ prod.token("(".to_sym) do |result,scanner,parser|
+ scanner.next
+ result = parser.parse_exp
+ parser.raise "Every '(' must be followed by a ')'" unless scanner.current == ")".to_sym
+ scanner.next
+ result
+ end
+
+ prod.token(:ident,:assign) do |result,scanner,parser|
+ name = scanner.current.to_s.strip
+ scanner.next
+ scanner.next
+ AssignIdentExp.new(name,parser.parse_exp)
+ end
+
+ prod.token(:ident) do |result,scanner,parser|
+ result = IdentExp.new(scanner.current.to_s.strip)
+ scanner.next
+ result
+ end
+
+ end
end
diff --git a/examples/ariteval/evaluator.rb b/examples/ariteval/evaluator.rb
index 7e1a373..f0cdfdb 100644
--- a/examples/ariteval/evaluator.rb
+++ b/examples/ariteval/evaluator.rb
@@ -1,60 +1,61 @@
-
+# It's a symple visitor for the abstract syntax tree created with the nodes in exp.rb.
+# It evaluates the expressions in the obvious way.
class Evaluator
- attr_reader :ident_table
-
- def initialize
- @result = 0
- @ident_table = {}
- end
-
- def visit_plus_exp(exp)
- left,right = left_and_right(exp)
- @result = left + right
- end
-
- def visit_minus_exp(exp)
- left,right = left_and_right(exp)
- @result = left - right
- end
-
- def visit_mul_exp(exp)
- left,right = left_and_right(exp)
- @result = left * right
- end
-
- def visit_div_exp(exp)
- left,right = left_and_right(exp)
- @result = left / right
- end
-
- def visit_num_exp(exp)
- @result = exp.value
- end
-
- def visit_assign_ident_exp(exp)
- exp.value.accept(self)
- ident_table[exp.name] = @result
- end
-
- def visit_ident_exp(exp)
- @result = ident_table[exp.value]
- end
-
- def result
- result = @result
- @result = 0
- return result
- end
-
- private
-
- def left_and_right(exp)
- exp.left.accept(self)
- left = @result
+ attr_reader :ident_table
+
+ def initialize
+ @result = 0
+ @ident_table = {}
+ end
+
+ def visit_plus_exp(exp)
+ left,right = left_and_right(exp)
+ @result = left + right
+ end
+
+ def visit_minus_exp(exp)
+ left,right = left_and_right(exp)
+ @result = left - right
+ end
+
+ def visit_mul_exp(exp)
+ left,right = left_and_right(exp)
+ @result = left * right
+ end
+
+ def visit_div_exp(exp)
+ left,right = left_and_right(exp)
+ @result = left / right
+ end
+
+ def visit_num_exp(exp)
+ @result = exp.value
+ end
+
+ def visit_assign_ident_exp(exp)
+ exp.value.accept(self)
+ ident_table[exp.name] = @result
+ end
+
+ def visit_ident_exp(exp)
+ @result = ident_table[exp.value]
+ end
+
+ def result
+ result = @result
+ @result = 0
+ return result
+ end
+
+ private
+
+ def left_and_right(exp)
+ exp.left.accept(self)
+ left = @result
- exp.right.accept(self)
- right = @result
- [left,right]
- end
+ exp.right.accept(self)
+ right = @result
+ [left,right]
+ end
end