jriasco2-rubycalc 0.0.2

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6a9c25081bb2a79adf6b95a1fba4d332ae95cc98
4
+ data.tar.gz: f07ba77bd4da1e756ad1b2cb3001c01538f2e925
5
+ SHA512:
6
+ metadata.gz: 35bd0e42e0a4ea45849ca0fbdc4c50a03113519c24df0f3bf647541bd032e16160c72ceebcbf82e4117baefa35beaafb4ff446526b911795cc067f80d27db8a5
7
+ data.tar.gz: 4bd709a24925f5638ba7c8ef4aab6c3bf0913d88bfdb54519b7c6f5ed68b20af0222d9c9aa57a6413845ca884fd3e5fc72eafc6540a552fef4ea417d99f65984
data/bin/rubycalc ADDED
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'calculator'
5
+ require 'calcex' #Excepciones
6
+
7
+ $stdout.print "> " #Imprime
8
+ $stdout.flush
9
+
10
+ text = gets #Obtenemos el texto
11
+
12
+ $calc = Calculator.new()
13
+
14
+ begin #Begin para manejar las excepciones de las mas bajas en gerarquia a la mas
15
+ #Forma 1
16
+ puts "= " + $calc.eval(text).to_s
17
+ #Forma 2
18
+
19
+ rescue ParseError => pe #=> pe nos captura el objeto de la excepcion
20
+ puts "Parse Error"
21
+ rescue UnrecognizedTokenException => ute
22
+ puts "UnrecognizedTokenException"
23
+ rescue
24
+ puts "Unkown exception"
25
+ end
data/lib/ast.rb ADDED
@@ -0,0 +1,84 @@
1
+ require 'set'
2
+
3
+ class BinaryNode
4
+ attr_reader :left, :right
5
+
6
+ def initialize(left,right)
7
+ @left = left
8
+ @right = right
9
+ end
10
+ end
11
+
12
+ class UnaryNode
13
+ attr_reader :subTree
14
+
15
+ def initialize(subTree)
16
+ @subTree = subTree
17
+ end
18
+ end
19
+
20
+ class AddNode < BinaryNode
21
+ def initialize(left, right)
22
+ super(left,right)
23
+ end
24
+
25
+ def evaluate()
26
+ return @left.evaluate() + @right.evaluate()
27
+ end
28
+ end
29
+
30
+ class SubNode < BinaryNode
31
+ def initialize(left, right)
32
+ super(left,right)
33
+ end
34
+
35
+ def evaluate()
36
+ return @left.evaluate() - @right.evaluate()
37
+ end
38
+ end
39
+
40
+ class TimesNode < BinaryNode
41
+ def initialize(left, right)
42
+ super(left,right)
43
+ end
44
+
45
+ def evaluate()
46
+ return @left.evaluate() * @right.evaluate()
47
+ end
48
+ end
49
+
50
+ class DivideNode < BinaryNode
51
+ def initialize(left, right)
52
+ super(left,right)
53
+ end
54
+
55
+ def evaluate()
56
+ return @left.evaluate() / @right.evaluate()
57
+ end
58
+ end
59
+
60
+ class NumNode
61
+ def initialize(num)
62
+ @num = num
63
+ end
64
+
65
+ def evaluate()
66
+ return @num
67
+ end
68
+ end
69
+
70
+ class StoreNode < UnaryNode
71
+ def initialize(subTree)
72
+ super(subTree)
73
+ end
74
+ def evaluate()
75
+ $calc.memoy = @subTree.evaluate()
76
+ end
77
+ end
78
+
79
+ class RecallNode
80
+ def evaluate()
81
+ $calc.memory
82
+ end
83
+ end
84
+
data/lib/calcex.rb ADDED
@@ -0,0 +1,3 @@
1
+
2
+ class ParseError < Exception; end
3
+ class UnrecognizedTokenException < Exception; end
data/lib/calculator.rb ADDED
@@ -0,0 +1,16 @@
1
+ require 'parser'
2
+ require 'ast'
3
+
4
+ class Calculator
5
+ attr_accessor :memory
6
+
7
+ def initialize()
8
+ @memory = 0
9
+ end
10
+
11
+ def eval(expr)
12
+ parser = Parser.new(StringIO.new(expr))
13
+ ast = parser.parse()
14
+ return ast.evaluate()
15
+ end
16
+ end
data/lib/parser.rb ADDED
@@ -0,0 +1,145 @@
1
+ require 'ast'
2
+ require 'scanner'
3
+ require 'token'
4
+ require 'calcex'
5
+
6
+ class Parser
7
+ def initialize(istream)
8
+ @scan = Scanner.new(istream)
9
+ end
10
+
11
+ def parse()
12
+ return Prog()
13
+ end
14
+
15
+ # private | public | protected -> Fuera de un metodo
16
+ def Prog()
17
+ result = Expr()
18
+ t = @scan.getToken()
19
+
20
+ if t.type != :eof then
21
+ print "Expected EOF. Found ", t.type, ".\n"
22
+ raise ParseError.new
23
+ end
24
+
25
+ return result
26
+ end
27
+
28
+ def Expr()
29
+ return RestExpr(Term())
30
+ end
31
+
32
+ def RestExpr(e)
33
+ t = @scan.getToken()
34
+
35
+ if t.type == :add then
36
+ return RestExpr(AddNode.new(e,Term()))
37
+ end
38
+
39
+ if t.type == :sub then
40
+ return RestExpr(SubNode.new(e,Term()))
41
+ end
42
+
43
+ @scan.putBackToken()
44
+
45
+ return e
46
+ end
47
+
48
+ def Term ()
49
+ RestTerm(Storable())
50
+ end
51
+ # def Term()
52
+ # # Write your Term() code here. This code is just temporary
53
+ # # so you can try the calculator out before finishing it.
54
+
55
+ # t = @scan.getToken()
56
+
57
+ # if t.type == :number then
58
+ # val = t.lex.to_i
59
+ # return NumNode.new(val)
60
+ # end
61
+
62
+ # puts "Term not implemented\n"
63
+
64
+ # raise ParseError.new
65
+ # end
66
+
67
+ # def RestTerm(e)
68
+
69
+ # puts "RestTerm not implemented"
70
+ # raise ParseError.new # "Parse Error"
71
+ # end
72
+
73
+ def RestTerm (e)
74
+ t = @scan.getToken
75
+ if t.type == :times then
76
+ return RestTerm(TimesNode.new(e,Storable()))
77
+ end
78
+
79
+ if t.type == :divide then
80
+ return RestTerm(DivideNode.new(e,Storable()))
81
+ end
82
+
83
+ @scan.putBackToken
84
+
85
+ e
86
+ end
87
+ # def Storable()
88
+
89
+ # puts "Storable not implemented"
90
+ # raise ParseError.new # "Parse Error"
91
+ # end
92
+
93
+ def Storable()
94
+ factor = Factor()
95
+
96
+ t = @scan.getToken
97
+
98
+ if t.type == :keyword then
99
+ if t.lex == "S" then
100
+ return StoreNode.new(factor)
101
+ else
102
+ raise.ParseError.new
103
+ end
104
+ end
105
+
106
+ @scan.putBackToken
107
+
108
+ factor
109
+ end
110
+ # def Factor()
111
+
112
+ # puts "Factor not implemented"
113
+ # raise ParserError.new # "Parse Error"
114
+ # end
115
+
116
+ def Factor()
117
+
118
+ t = @scan.getToken
119
+
120
+ if t.type == :number then
121
+ return NumNode.new(t.lex.to_i)
122
+ end
123
+
124
+ if t.type == :keyword then
125
+ if t.lex == "R" then
126
+ return RecallNode.new
127
+ else
128
+ raise.ParseError.new
129
+ end
130
+ end
131
+
132
+ if t.type == :lparen then
133
+ expr = Expr()
134
+ t = @scan.getToken
135
+ if t.type == :rparen then
136
+ return expr
137
+ else
138
+ raise.ParseError.new
139
+ end
140
+ end
141
+
142
+ raise ParseError.new
143
+
144
+ end
145
+ end
data/lib/scanner.rb ADDED
@@ -0,0 +1,138 @@
1
+ require 'stringio'
2
+ require 'calcex'
3
+
4
+ #Conjunto -> sirve para guardar las palabras reservadas
5
+ class Scanner
6
+ def initialize(inStream)
7
+ @istream = inStream
8
+ @keywords = Set.new(["S","R"])
9
+ @lineCount = 1
10
+ @colCount = -1
11
+ @needToken = true
12
+ @lastToken = nil
13
+ end
14
+
15
+ def putBackToken()
16
+ @needToken = false
17
+ end
18
+
19
+ #A menos que necesite un token retorna el ultimo token almacenado o sino hace la comprobacion del flujo de entrada
20
+ def getToken()
21
+ unless @needToken
22
+ @needToken = true
23
+ return @lastToken
24
+ end
25
+
26
+ state = 0
27
+ foundOne = false
28
+ c = @istream.getc #optiene un caracter
29
+
30
+ if @istream.eof then #es final de fichero
31
+ @lastToken = Token.new(:eof,@lineCount,@colCount)
32
+ return @lastToken
33
+ end
34
+
35
+ until foundOne do #logica negativa -> while !foundOne
36
+ @colCount = @colCount + 1
37
+ case state
38
+ when 0
39
+ lex = ""
40
+ column = @colCount
41
+ line = @lineCount
42
+ if isLetter(c) then state=1
43
+ elsif isDigit(c) then state=2
44
+ elsif c == ?+ then state = 3
45
+ elsif c == ?- then state = 4
46
+ elsif c == ?* then state = 5
47
+ elsif c == ?/ then state = 6
48
+ elsif c == ?( then state = 7
49
+ elsif c == ?) then state = 8
50
+ elsif c == ?\n then
51
+ @colCount = -1
52
+ @lineCount = @lineCount+1
53
+ elsif isWhiteSpace(c) then state = state #ignore whitespace
54
+ elsif @istream.eof() then
55
+ @foundOne = true
56
+ type = :eof
57
+ else
58
+ puts "Unrecognized Token found at line ",line," and column ",column,"\n"
59
+ raise UnrecognizedTokenException # "Unrecognized Token"
60
+ end
61
+ when 1
62
+ if isLetter(c) or isDigit(c) then state = 1
63
+ else
64
+ if @keywords.include?(lex) then
65
+ foundOne = true
66
+ type = :keyword
67
+ else
68
+ foundOne = true
69
+ type = :identifier
70
+ end
71
+ end
72
+ when 2
73
+ if isDigit(c) then state = 2
74
+ else
75
+ type = :number
76
+ foundOne = true
77
+ end
78
+ when 3
79
+ type = :add
80
+ foundOne = true
81
+ when 4
82
+ type = :sub
83
+ foundOne = true
84
+ when 5
85
+ type = :times
86
+ foundOne = true
87
+ when 6
88
+ type = :divide
89
+ foundOne = true
90
+ when 7
91
+ type = :lparen
92
+ foundOne = true
93
+ when 8
94
+ type = :rparen
95
+ foundOne = true
96
+ end
97
+
98
+ if !foundOne then
99
+ lex.concat(c)
100
+ c = @istream.getc()
101
+ end
102
+
103
+ end
104
+
105
+ @istream.ungetc(c)
106
+ @colCount = @colCount - 1
107
+ if type == :number or type == :identifier or type == :keyword then
108
+ t = LexicalToken.new(type,lex,line,column)
109
+ else
110
+ t = Token.new(type,line,column)
111
+ end
112
+
113
+ @lastToken = t
114
+ return t
115
+ end
116
+
117
+ private
118
+ def isLetter(c)
119
+ if c.nil? then
120
+ return false
121
+ end
122
+ (?a <= c and c <= ?z) or (?A <= c and c <= ?Z)
123
+ end
124
+
125
+ def isDigit(c)
126
+ if c.nil? then
127
+ return false
128
+ end
129
+ ?0 <= c and c <= ?9
130
+ end
131
+
132
+ def isWhiteSpace(c)
133
+ if c.nil? then
134
+ return false
135
+ end
136
+ c == ?\ or c == ?\n or c == ?\t
137
+ end
138
+ end
data/lib/token.rb ADDED
@@ -0,0 +1,19 @@
1
+ class Token
2
+ attr_reader :type, :line, :col
3
+
4
+ def initialize(type,lineNum,colNum)
5
+ @type = type
6
+ @line = lineNum
7
+ @col = colNum
8
+ end
9
+ end
10
+
11
+ class LexicalToken < Token
12
+ attr_reader :lex
13
+
14
+ def initialize(type,lex,lineNum,colNum)
15
+ super(type,lineNum,colNum)
16
+
17
+ @lex = lex
18
+ end
19
+ end
metadata ADDED
@@ -0,0 +1,51 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jriasco2-rubycalc
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Kent D. Lee - Juan Francisco Cardona Mc - John Jairo Riascos
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-05-13 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: An calculator implementation on ruby
14
+ email: jriasco2@fcardona@eafit.edu.co
15
+ executables:
16
+ - rubycalc
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - bin/rubycalc
21
+ - lib/ast.rb
22
+ - lib/calcex.rb
23
+ - lib/calculator.rb
24
+ - lib/parser.rb
25
+ - lib/scanner.rb
26
+ - lib/token.rb
27
+ homepage: http://www1.eafit.edu.co/fcardona/cursos/st0244/rubycal
28
+ licenses:
29
+ - ARTISTIC
30
+ metadata: {}
31
+ post_install_message:
32
+ rdoc_options: []
33
+ require_paths:
34
+ - lib
35
+ required_ruby_version: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ required_rubygems_version: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ requirements: []
46
+ rubyforge_project:
47
+ rubygems_version: 2.4.8
48
+ signing_key:
49
+ specification_version: 4
50
+ summary: Another calculator in ruby
51
+ test_files: []