Skip to content

Commit

Permalink
added rdoc to ariteval
Browse files Browse the repository at this point in the history
  • Loading branch information
mcollina committed Jun 9, 2007
1 parent 360c314 commit f5b9d10
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 139 deletions.
2 changes: 1 addition & 1 deletion README.txt
Expand Up @@ -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:
[<b>exp.rb</b>] contains all the Abstract Syntax Tree node definitions.
[<b>ariteval.rb</b>] contains the productions definitions using LLIP::Parser.
[<b>ariteval.rb</b>] contains the Ariteval class which defines all the productions using LLIP::Parser.
[<b>evaluator.rb</b>] a simple visitor which uses the classes defined in exp.rb.

== Author
Expand Down
2 changes: 1 addition & 1 deletion Rakefile
Expand Up @@ -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

Expand Down
186 changes: 105 additions & 81 deletions 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
113 changes: 57 additions & 56 deletions 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

0 comments on commit f5b9d10

Please sign in to comment.