llip 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|