llip 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +4 -0
- data/MIT-LICENSE +21 -0
- data/Manifest.txt +45 -0
- data/README.txt +148 -0
- data/Rakefile +66 -0
- data/examples/ariteval/ariteval.rb +132 -0
- data/examples/ariteval/evaluator.rb +61 -0
- data/examples/ariteval/exp.rb +104 -0
- data/lib/llip.rb +6 -0
- data/lib/llip/abstract_parser.rb +170 -0
- data/lib/llip/abstract_scanner.rb +83 -0
- data/lib/llip/buffer.rb +35 -0
- data/lib/llip/llip_error.rb +43 -0
- data/lib/llip/parser.rb +93 -0
- data/lib/llip/production_compiler.rb +168 -0
- data/lib/llip/production_specification.rb +79 -0
- data/lib/llip/recursive_production_compiler.rb +35 -0
- data/lib/llip/regexp_abstract_scanner.rb +116 -0
- data/lib/llip/regexp_parser.rb +197 -0
- data/lib/llip/regexp_scanner.rb +33 -0
- data/lib/llip/regexp_specification.rb +210 -0
- data/lib/llip/token.rb +47 -0
- data/lib/llip/visitable.rb +37 -0
- data/spec/ariteval/ariteval_spec.rb +111 -0
- data/spec/ariteval/evaluator_spec.rb +106 -0
- data/spec/ariteval/exp_spec.rb +232 -0
- data/spec/llip/abstract_parser_spec.rb +273 -0
- data/spec/llip/abstract_scanner_spec.rb +152 -0
- data/spec/llip/buffer_spec.rb +60 -0
- data/spec/llip/llip_error_spec.rb +77 -0
- data/spec/llip/parser_spec.rb +163 -0
- data/spec/llip/production_compiler_spec.rb +271 -0
- data/spec/llip/production_specification_spec.rb +75 -0
- data/spec/llip/recursive_production_compiler_spec.rb +86 -0
- data/spec/llip/regexp_abstract_scanner_spec.rb +320 -0
- data/spec/llip/regexp_parser_spec.rb +265 -0
- data/spec/llip/regexp_scanner_spec.rb +40 -0
- data/spec/llip/regexp_specification_spec.rb +734 -0
- data/spec/llip/token_spec.rb +70 -0
- data/spec/llip/visitable_spec.rb +38 -0
- data/spec/spec_helper.rb +10 -0
- metadata +110 -0
data/History.txt
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2005-2007 Matteo Collina
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
17
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
18
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
19
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
20
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
data/Manifest.txt
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
History.txt
|
2
|
+
MIT-LICENSE
|
3
|
+
Manifest.txt
|
4
|
+
README.txt
|
5
|
+
Rakefile
|
6
|
+
examples/ariteval
|
7
|
+
examples/ariteval/ariteval.rb
|
8
|
+
examples/ariteval/evaluator.rb
|
9
|
+
examples/ariteval/exp.rb
|
10
|
+
lib/llip
|
11
|
+
lib/llip.rb
|
12
|
+
lib/llip/abstract_parser.rb
|
13
|
+
lib/llip/abstract_scanner.rb
|
14
|
+
lib/llip/buffer.rb
|
15
|
+
lib/llip/llip_error.rb
|
16
|
+
lib/llip/parser.rb
|
17
|
+
lib/llip/production_compiler.rb
|
18
|
+
lib/llip/production_specification.rb
|
19
|
+
lib/llip/recursive_production_compiler.rb
|
20
|
+
lib/llip/regexp_abstract_scanner.rb
|
21
|
+
lib/llip/regexp_parser.rb
|
22
|
+
lib/llip/regexp_scanner.rb
|
23
|
+
lib/llip/regexp_specification.rb
|
24
|
+
lib/llip/token.rb
|
25
|
+
lib/llip/visitable.rb
|
26
|
+
spec/ariteval
|
27
|
+
spec/ariteval/ariteval_spec.rb
|
28
|
+
spec/ariteval/evaluator_spec.rb
|
29
|
+
spec/ariteval/exp_spec.rb
|
30
|
+
spec/llip
|
31
|
+
spec/llip/abstract_parser_spec.rb
|
32
|
+
spec/llip/abstract_scanner_spec.rb
|
33
|
+
spec/llip/buffer_spec.rb
|
34
|
+
spec/llip/llip_error_spec.rb
|
35
|
+
spec/llip/parser_spec.rb
|
36
|
+
spec/llip/production_compiler_spec.rb
|
37
|
+
spec/llip/production_specification_spec.rb
|
38
|
+
spec/llip/recursive_production_compiler_spec.rb
|
39
|
+
spec/llip/regexp_abstract_scanner_spec.rb
|
40
|
+
spec/llip/regexp_parser_spec.rb
|
41
|
+
spec/llip/regexp_scanner_spec.rb
|
42
|
+
spec/llip/regexp_specification_spec.rb
|
43
|
+
spec/llip/token_spec.rb
|
44
|
+
spec/llip/visitable_spec.rb
|
45
|
+
spec/spec_helper.rb
|
data/README.txt
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
= LLInterpretedParser
|
2
|
+
|
3
|
+
The LL(k) Interpreted Parser (llip) is an automated tool to easily create an LL(k) parser and the related scanner without the need of generating anything.
|
4
|
+
Everything is done on the fly through a simple DSL.
|
5
|
+
|
6
|
+
== A Little comparrison against other tools
|
7
|
+
|
8
|
+
Tools like JavaCC, ANTLR, Coco/R and others use an external description file which they compile into the destination code.
|
9
|
+
This file it's usually written using a complex product related language. Using Ruby metaprogramming, a parser generator can go one step further.
|
10
|
+
In fact, the llip gem gives you the possibility to write a parser writing only Ruby code.
|
11
|
+
|
12
|
+
== Don't compile anything
|
13
|
+
|
14
|
+
This tool is based on a simple and powerful DSL that can be used to specify:
|
15
|
+
* some tokens to be recognized in the form of regular expressions, as defined in LLIP::RegexpParser,
|
16
|
+
* some productions using LLIP::ProductionSpecification,
|
17
|
+
* some LL(K) related behaviour like lookaheads.
|
18
|
+
|
19
|
+
Everything specified is automatically translated into live objects which can be used to do LL(K) parsing.
|
20
|
+
|
21
|
+
== The LLIP Library
|
22
|
+
|
23
|
+
The LLIP::Parser is a facade of the entire library. In fact it handles all the wiring to make it work.
|
24
|
+
It also takes care of generating the right LLIP::TokenSpecification starting from its definition,
|
25
|
+
which is a simple string written as defined in LLIP::RegexpParser.
|
26
|
+
|
27
|
+
To use this library it's necessary to subclass LLIP:Parser and so it's possible to specify all the needed behaviours.
|
28
|
+
An instance of that subclass gains the +parse+ method, which parses a string or an IO with the productions previously defined.
|
29
|
+
|
30
|
+
== Installation
|
31
|
+
|
32
|
+
<code>sudo gem install llip</code>
|
33
|
+
|
34
|
+
== History of this gem
|
35
|
+
|
36
|
+
This library was originally developed as a project for a computer language course at the engeneering[http://www.ing.unibo.it] faculty of the university of Bologna, Italy.
|
37
|
+
|
38
|
+
== A Simple Example
|
39
|
+
|
40
|
+
#! /usr/bin/ruby
|
41
|
+
|
42
|
+
require 'rubygems'
|
43
|
+
|
44
|
+
require 'llip'
|
45
|
+
|
46
|
+
class MyParser < LLIP::Parser
|
47
|
+
|
48
|
+
token :num, "(1|2|3|4|5|6|7|8|9|0)+" # simple definition of a number
|
49
|
+
|
50
|
+
scope :number # definition of the scope, the first production which will be called
|
51
|
+
|
52
|
+
production(:number) do |p|
|
53
|
+
|
54
|
+
# inside the :number production,
|
55
|
+
# we are specifying what to do when we encounter a :num token
|
56
|
+
p.token :num do |result,scanner,parser|
|
57
|
+
puts "The number is..."
|
58
|
+
number = scanner.current.value
|
59
|
+
puts number
|
60
|
+
scanner.next # we are reading the next token
|
61
|
+
number
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
puts "--->>> Example 1"
|
68
|
+
|
69
|
+
parser = MyParser.new
|
70
|
+
|
71
|
+
parser.parse("1")
|
72
|
+
|
73
|
+
parser.parse("34065")
|
74
|
+
|
75
|
+
parser.parse("123456")
|
76
|
+
|
77
|
+
puts "--->>> Example 2"
|
78
|
+
|
79
|
+
begin
|
80
|
+
parser.parse("3+2")
|
81
|
+
rescue LLIP::LLIPError => error
|
82
|
+
puts error
|
83
|
+
end
|
84
|
+
|
85
|
+
class MyParser
|
86
|
+
|
87
|
+
token :plus, '\+' # the '\' is required because it escapes the '+',
|
88
|
+
# which is a token of a regular expressions.
|
89
|
+
|
90
|
+
scope :exp
|
91
|
+
|
92
|
+
production :exp, :recursive do |p|
|
93
|
+
p.default { |scanner,parser| parser.parse_number } # this block is exectued before any
|
94
|
+
# other block. The result of this block
|
95
|
+
# will be putted in the first parameter of the
|
96
|
+
# first production matched.
|
97
|
+
|
98
|
+
p.token :plus do |left,scanner,parser|
|
99
|
+
scanner.next
|
100
|
+
right = parser.parse_number # we are calling another production!!
|
101
|
+
sum = left.to_i + right.to_i
|
102
|
+
puts "The sum is #{sum}"
|
103
|
+
sum
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
result = parser.parse "3+2+4"
|
109
|
+
|
110
|
+
puts "the result is #{result}"
|
111
|
+
|
112
|
+
== A more complex example, the Ariteval parser
|
113
|
+
|
114
|
+
Bundled with this library there is an example of an Arithmetic Evaluator,
|
115
|
+
which evaluates simple expressions like "3-7*(6-2)". In the "examples/ariteval" directory there are:
|
116
|
+
[<b>exp.rb</b>] contains all the Abstract Syntax Tree node definitions.
|
117
|
+
[<b>ariteval.rb</b>] contains the Ariteval class which defines all the productions using LLIP::Parser.
|
118
|
+
[<b>evaluator.rb</b>] a simple visitor which uses the classes defined in exp.rb.
|
119
|
+
|
120
|
+
== Author
|
121
|
+
|
122
|
+
This library has been written by Matteo Collina, matteo dot collina at gmail dot com.
|
123
|
+
|
124
|
+
== License
|
125
|
+
|
126
|
+
(The MIT license)
|
127
|
+
|
128
|
+
Copyright (c) 2006-2007 Matteo Collina
|
129
|
+
|
130
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
131
|
+
a copy of this software and associated documentation files (the
|
132
|
+
"Software"), to deal in the Software without restriction, including
|
133
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
134
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
135
|
+
permit persons to whom the Software is furnished to do so, subject to
|
136
|
+
the following conditions:
|
137
|
+
|
138
|
+
The above copyright notice and this permission notice shall be
|
139
|
+
included in all copies or substantial portions of the Software.
|
140
|
+
|
141
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
142
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
143
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
144
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
145
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
146
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
147
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
148
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'hoe'
|
3
|
+
require 'lib/llip'
|
4
|
+
require 'spec/rake/spectask'
|
5
|
+
require 'spec/rake/verify_rcov'
|
6
|
+
require 'iconv'
|
7
|
+
|
8
|
+
Hoe.new('llip',LLIP::VERSION) do |p|
|
9
|
+
p.author = "Matteo Collina"
|
10
|
+
p.name = "llip"
|
11
|
+
p.email = "matteo.collina@gmail.com"
|
12
|
+
p.extra_deps = ["rspec",">= 1.0.0"]
|
13
|
+
p.description = p.paragraphs_of('README.txt', 1..3).join("\n\n")
|
14
|
+
p.summary = "LLIP is a tool to geneate a LL(k) parser."
|
15
|
+
p.url = "http://llip.rubyforge.org"
|
16
|
+
p.rdoc_pattern = /(^lib\/llip\/.*|.*\.txt|^examples\/ariteval\/.*)/
|
17
|
+
p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
|
18
|
+
end
|
19
|
+
|
20
|
+
Rake.application["default"].prerequisites.shift
|
21
|
+
|
22
|
+
task :default => [:spec]
|
23
|
+
|
24
|
+
desc "Run the LLIP specifications"
|
25
|
+
Spec::Rake::SpecTask.new('spec') do |t|
|
26
|
+
t.spec_files = FileList['spec/llip/*.rb']
|
27
|
+
t.spec_opts = ["--diff c"]
|
28
|
+
end
|
29
|
+
|
30
|
+
desc "Run all the specifications"
|
31
|
+
Spec::Rake::SpecTask.new('spec:all') do |t|
|
32
|
+
t.spec_files = FileList['spec/**/*.rb'] - ["specs/spec_helper.rb"]
|
33
|
+
t.spec_opts = ["--diff c"]
|
34
|
+
end
|
35
|
+
|
36
|
+
desc "Run all the specifications and generate the output in html"
|
37
|
+
Spec::Rake::SpecTask.new('spec:html') do |t|
|
38
|
+
t.spec_files = FileList['spec/**/*.rb'] - ["specs/spec_helper.rb"]
|
39
|
+
t.spec_opts = ["-f html","--diff c","-o","specs.html"]
|
40
|
+
end
|
41
|
+
|
42
|
+
desc "Run all the specification with RCov support"
|
43
|
+
Spec::Rake::SpecTask.new('rcov') do |t|
|
44
|
+
t.spec_files = FileList['spec/**/*.rb'] - ["specs/spec_helper.rb"]
|
45
|
+
t.spec_opts = ["-c"]
|
46
|
+
t.rcov = true
|
47
|
+
t.rcov_opts = ['--exclude', "rcov,spec,gem"]
|
48
|
+
end
|
49
|
+
|
50
|
+
desc "Run all the specification and checks if the coverage is at the threshold"
|
51
|
+
RCov::VerifyTask.new(:verify_rcov => :rcov) do |t|
|
52
|
+
t.threshold = 100.0
|
53
|
+
end
|
54
|
+
|
55
|
+
desc "Creates the Manifest"
|
56
|
+
task :create_manifest do
|
57
|
+
files = FileList["{examples,lib,spec}/**/*"] + ["README.txt","Manifest.txt","History.txt","MIT-LICENSE","Rakefile"]
|
58
|
+
files.sort!
|
59
|
+
File.open("Manifest.txt", "w") do |io|
|
60
|
+
io.write(files.join("\n"))
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
task :commit => :verify_rcov do |t|
|
65
|
+
exec "svn commit"
|
66
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'parser'
|
2
|
+
require 'evaluator'
|
3
|
+
|
4
|
+
# It's a simple arithmetical evaluator. It's able to parse expressions like these:
|
5
|
+
# * ( a = 3 * 2 ) - ( 24 + a ),
|
6
|
+
# * 3 * (4 - 2) + 5*(4/2)/(3-2).
|
7
|
+
#
|
8
|
+
# It realizes the following grammar:
|
9
|
+
#
|
10
|
+
# non terminal symbols = { SCOPE, EXP, TERM, POW, FACTOR, NUMBER }
|
11
|
+
# terminal symbols = any number, the charachters " , . + - * / ^ = [ ] ( ) ' "
|
12
|
+
#
|
13
|
+
# an id is an unlimited string composed of every charachter "a".."Z" and the "_"
|
14
|
+
#
|
15
|
+
# P = {
|
16
|
+
# SCOPE ::= EXP
|
17
|
+
# EXP ::= EXP + TERM
|
18
|
+
# EXP ::= EXP - TERM
|
19
|
+
# TERM ::= POW
|
20
|
+
# TERM ::= TERM * FACTOR
|
21
|
+
# TERM ::= TERM / FACTOR
|
22
|
+
# FACTOR ::= any sequence of 0,1,2,3,4,5,6,7,8,9
|
23
|
+
# FACTOR ::= an id
|
24
|
+
# FACTOR ::= an id =
|
25
|
+
# FACTOR ::= ( EXP )
|
26
|
+
# }
|
27
|
+
#
|
28
|
+
class Ariteval < Parser
|
29
|
+
|
30
|
+
def initialize
|
31
|
+
super
|
32
|
+
@evaluator = Evaluator.new
|
33
|
+
end
|
34
|
+
|
35
|
+
def evaluate(source)
|
36
|
+
parse(source).accept(@evaluator)
|
37
|
+
@evaluator.result
|
38
|
+
end
|
39
|
+
|
40
|
+
# tokens definitions
|
41
|
+
|
42
|
+
numbers = ("0".."9").to_a.join("|")
|
43
|
+
token :number, "(#{numbers})+ *"
|
44
|
+
|
45
|
+
token :plus, '\+ *'
|
46
|
+
|
47
|
+
token :minus, '- *'
|
48
|
+
|
49
|
+
token :mul, '\* *'
|
50
|
+
|
51
|
+
token :div, '/ *'
|
52
|
+
|
53
|
+
token "(".to_sym, '\( *'
|
54
|
+
|
55
|
+
token ")".to_sym, '\) *'
|
56
|
+
|
57
|
+
identifiers = (("a".."z").to_a + ("A".."Z").to_a).join("|")
|
58
|
+
token :ident, "(#{identifiers}) *"
|
59
|
+
|
60
|
+
token :assign, "= *"
|
61
|
+
|
62
|
+
# production definitions
|
63
|
+
|
64
|
+
lookahead(true)
|
65
|
+
|
66
|
+
scope :exp
|
67
|
+
|
68
|
+
production(:exp,:recursive) do |prod|
|
69
|
+
prod.default { |scanner,parser| parser.parse_term }
|
70
|
+
|
71
|
+
prod.token(:plus) do |term_seq,scanner,parser|
|
72
|
+
scanner.next
|
73
|
+
next_term = parser.parse_term
|
74
|
+
PlusExp.new(term_seq,next_term)
|
75
|
+
end
|
76
|
+
|
77
|
+
prod.token(:minus) do |term_seq,scanner,parser|
|
78
|
+
scanner.next
|
79
|
+
next_term = parser.parse_term
|
80
|
+
MinusExp.new(term_seq,next_term)
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
production(:term,:recursive) do |prod|
|
86
|
+
prod.default { |scanner,parser| parser.parse_factor }
|
87
|
+
|
88
|
+
prod.token(:mul) do |factor_seq,scanner,parser|
|
89
|
+
scanner.next
|
90
|
+
next_factor = parser.parse_factor
|
91
|
+
MulExp.new(factor_seq,next_factor)
|
92
|
+
end
|
93
|
+
|
94
|
+
prod.token(:div) do |factor_seq,scanner,parser|
|
95
|
+
scanner.next
|
96
|
+
next_factor = parser.parse_factor
|
97
|
+
DivExp.new(factor_seq,next_factor)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
production(:factor,:single) do |prod|
|
102
|
+
|
103
|
+
prod.token(:number) do |result,scanner|
|
104
|
+
current = scanner.current
|
105
|
+
scanner.next
|
106
|
+
NumExp.new(current.value.to_i)
|
107
|
+
end
|
108
|
+
|
109
|
+
prod.token("(".to_sym) do |result,scanner,parser|
|
110
|
+
scanner.next
|
111
|
+
result = parser.parse_exp
|
112
|
+
parser.raise "Every '(' must be followed by a ')'" unless scanner.current == ")".to_sym
|
113
|
+
scanner.next
|
114
|
+
result
|
115
|
+
end
|
116
|
+
|
117
|
+
prod.token(:ident,:assign) do |result,scanner,parser|
|
118
|
+
name = scanner.current.to_s.strip
|
119
|
+
scanner.next
|
120
|
+
scanner.next
|
121
|
+
AssignIdentExp.new(name,parser.parse_exp)
|
122
|
+
end
|
123
|
+
|
124
|
+
prod.token(:ident) do |result,scanner,parser|
|
125
|
+
result = IdentExp.new(scanner.current.to_s.strip)
|
126
|
+
scanner.next
|
127
|
+
result
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# It's a symple visitor for the abstract syntax tree created with the nodes in exp.rb.
|
2
|
+
# It evaluates the expressions in the obvious way.
|
3
|
+
class Evaluator
|
4
|
+
|
5
|
+
attr_reader :ident_table
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@result = 0
|
9
|
+
@ident_table = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def visit_plus_exp(exp)
|
13
|
+
left,right = left_and_right(exp)
|
14
|
+
@result = left + right
|
15
|
+
end
|
16
|
+
|
17
|
+
def visit_minus_exp(exp)
|
18
|
+
left,right = left_and_right(exp)
|
19
|
+
@result = left - right
|
20
|
+
end
|
21
|
+
|
22
|
+
def visit_mul_exp(exp)
|
23
|
+
left,right = left_and_right(exp)
|
24
|
+
@result = left * right
|
25
|
+
end
|
26
|
+
|
27
|
+
def visit_div_exp(exp)
|
28
|
+
left,right = left_and_right(exp)
|
29
|
+
@result = left / right
|
30
|
+
end
|
31
|
+
|
32
|
+
def visit_num_exp(exp)
|
33
|
+
@result = exp.value
|
34
|
+
end
|
35
|
+
|
36
|
+
def visit_assign_ident_exp(exp)
|
37
|
+
exp.value.accept(self)
|
38
|
+
ident_table[exp.name] = @result
|
39
|
+
end
|
40
|
+
|
41
|
+
def visit_ident_exp(exp)
|
42
|
+
@result = ident_table[exp.value]
|
43
|
+
end
|
44
|
+
|
45
|
+
def result
|
46
|
+
result = @result
|
47
|
+
@result = 0
|
48
|
+
return result
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def left_and_right(exp)
|
54
|
+
exp.left.accept(self)
|
55
|
+
left = @result
|
56
|
+
|
57
|
+
exp.right.accept(self)
|
58
|
+
right = @result
|
59
|
+
[left,right]
|
60
|
+
end
|
61
|
+
end
|