From f5b9d10d221a0308d940e259708a73f609f0ef3c Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Sat, 9 Jun 2007 14:52:09 +0000 Subject: [PATCH] added rdoc to ariteval --- README.txt | 2 +- Rakefile | 2 +- examples/ariteval/ariteval.rb | 186 +++++++++++++++++++-------------- examples/ariteval/evaluator.rb | 113 ++++++++++---------- 4 files changed, 164 insertions(+), 139 deletions(-) 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