calc_jzapat80 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7bf6c1ffe5810b1f0c2c62456548ff651c63b90e
4
+ data.tar.gz: eb9dca67ac1460e3190d166e2e01bc4f7a245d86
5
+ SHA512:
6
+ metadata.gz: be096b0fe55e4e67538c7b041a6b677af3347aebb5f25efa6587cc78fedddc7d536386f0f5f82045aa15d1aefa6867770c830e3fd487339b2956d7b9dc7be5c5
7
+ data.tar.gz: 142c94b1bbd680ed43db5c50f20b94ca94b2574ef5c852f25d91bf8c5978d4ef13c9a45cd56b639b0778c6fbf7fb841741b7904e674c52d2eaee016683a4191e
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'calculator'
5
+ require 'calcex'
6
+
7
+ $stdout.print "> "
8
+ $stdout.flush
9
+
10
+ text = gets
11
+
12
+ $calc = Calculator.new()
13
+
14
+ begin
15
+ puts "= " + $calc.eval(text).to_s
16
+ rescue ParseError
17
+ puts "Parse Error"
18
+ rescue UnrecognizedTokenException
19
+ puts "UnrecognizedTokenException"
20
+ rescue
21
+ puts "Unkown exception"
22
+ end
@@ -0,0 +1,87 @@
1
+ # coding: utf-8
2
+ require 'set'
3
+
4
+ class BinaryNode
5
+ attr_reader :left, :right
6
+
7
+ def initialize(left,right)
8
+ @left = left
9
+ @right = right
10
+ end
11
+ end
12
+
13
+ class UnaryNode
14
+ attr_reader :subTree
15
+
16
+ def initialize(subTree)
17
+ @subTree = subTree
18
+ end
19
+ end
20
+
21
+ class AddNode < BinaryNode
22
+ def initialize(left, right)
23
+ super(left,right)
24
+ end
25
+
26
+ def evaluate()
27
+ return @left.evaluate() + @right.evaluate() #Como ya sabemos, los paréntesis no son obligatorios.
28
+ #El return no hace falta.
29
+ end
30
+ end
31
+
32
+ class SubNode < BinaryNode
33
+ def initialize(left, right)
34
+ super(left,right)
35
+ end
36
+
37
+ def evaluate()
38
+ return @left.evaluate() - @right.evaluate()
39
+ end
40
+ end
41
+
42
+ class TimesNode < BinaryNode
43
+ def initialize(left, right)
44
+ super(left, right)
45
+ end
46
+
47
+ def evaluate()
48
+ return @left.evaluate() * @right.evaluate()
49
+ end
50
+ end
51
+
52
+ class DivideNode < BinaryNode
53
+ def initialize(left, right)
54
+ super(left, right)
55
+ end
56
+
57
+ def evaluate()
58
+ return @left.evaluate() / @right.evaluate()
59
+ end
60
+ end
61
+
62
+ class StoreNode < UnaryNode
63
+ def initialize(sub)
64
+ super(sub)
65
+ end
66
+
67
+ def evaluate
68
+ $calc.memory = subTree.evaluate #El $calc llama a la variable global calc que se llama en el irb>require 'calculator'
69
+ #irb>$calc = Calculator.new
70
+ end
71
+ end
72
+
73
+ class RecallNode
74
+ def evaluate
75
+ return $calc.memory
76
+ end
77
+ end
78
+
79
+ class NumNode
80
+ def initialize(num)
81
+ @num = num
82
+ end
83
+
84
+ def evaluate()
85
+ return @num
86
+ end
87
+ end
@@ -0,0 +1,7 @@
1
+
2
+ class ParseError < Exception; end #las excepciones deben heredar de la clase padre Exception
3
+ #No existe bloque try{ }catch{ } .
4
+ # no se hace throw
5
+ #
6
+ #Se hace: begin ... rescue ... raise ... end
7
+ class UnrecognizedTokenException < Exception; end
@@ -0,0 +1,19 @@
1
+ require 'parser'
2
+ require 'ast'
3
+
4
+ class Calculator
5
+ #attr_reader :memory
6
+ #attr_writer :memory
7
+
8
+ attr_accessor :memory
9
+
10
+ def initialize()
11
+ @memory = 0
12
+ end
13
+
14
+ def eval(expr)
15
+ parser = Parser.new(StringIO.new(expr))
16
+ ast = parser.parse()
17
+ return ast.evaluate()
18
+ end
19
+ end
@@ -0,0 +1,146 @@
1
+ # coding: utf-8
2
+ require 'ast'
3
+ require 'scanner'
4
+ require 'token'
5
+ require 'calcex'
6
+
7
+ class Parser
8
+ def initialize(istream)
9
+ @scan = Scanner.new(istream)
10
+ end
11
+
12
+ def parse()
13
+ return Prog()
14
+ end
15
+
16
+ private
17
+ def Prog()
18
+ result = Expr()
19
+ t = @scan.getToken()
20
+
21
+ if t.type != :eof then
22
+ print "Expected EOF. Found ", t.type, ".\n"
23
+ raise ParseError.new
24
+ end
25
+
26
+ return result
27
+ end
28
+
29
+ def Expr()
30
+ RestExpr(Term())
31
+ end
32
+
33
+ def RestExpr(e)
34
+ t = @scan.getToken()
35
+
36
+ if t.type == :add then
37
+ return RestExpr(AddNode.new(e,Term()))
38
+ end
39
+
40
+ if t.type == :sub then
41
+ return RestExpr(SubNode.new(e,Term()))
42
+ end
43
+
44
+ @scan.putBackToken()
45
+
46
+ return e
47
+ end
48
+
49
+ def Term()
50
+ # # Write your Term() code here. This code is just temporary
51
+ # # so you can try the calculator out before finishing it.
52
+
53
+ # t = @scan.getToken()
54
+
55
+ # if t.type == :number then
56
+ # val = t.lex.to_i
57
+ # return NumNode.new(val)
58
+ # end
59
+
60
+ # puts "Term not implemented\n"
61
+
62
+ # raise ParseError.new
63
+
64
+ RestTerm(Storable()) #Look at this. You dont have to return
65
+ end
66
+
67
+ def RestTerm(e)
68
+
69
+ #puts "RestTerm not implemented"
70
+ #raise ParseError.new # "Parse Error"
71
+
72
+ t=@scan.getToken
73
+
74
+ if t.type == :times
75
+ return RestTerm(TimesNode.new(e,Storable()))
76
+ end
77
+
78
+ if t.type == :divide
79
+ return RestTerm(DivideNode.new(e,Storable()))
80
+ end
81
+
82
+ @scan.putBackToken
83
+
84
+ e #No hay que hacer return. La ventaja de poner return es por documentación.
85
+
86
+ end
87
+
88
+
89
+
90
+ def Storable()
91
+
92
+ #puts "Storable not implemented"
93
+ #raise ParseError.new # "Parse Error"
94
+
95
+ result = Factor()
96
+
97
+ t=@scan.getToken
98
+
99
+ if t.type == :keyword then
100
+ if t.lex == "S" then
101
+ return StoreNode.new(result)
102
+ end
103
+ puts "Expected S, found: ", t.lex
104
+ raise ParseError.new
105
+ end
106
+
107
+ @scan.putBackToken
108
+ return result
109
+
110
+ end
111
+
112
+ def Factor()
113
+
114
+ #puts "Factor not implemented"
115
+ #raise ParseError.new # "Parse Error"
116
+
117
+ t = @scan.getToken
118
+ if t.type == :number then
119
+ return NumNode.new(t.lex.to_i)
120
+ end
121
+
122
+ if t.type == :keyword then
123
+ if t.lex == "R" then
124
+ return RecallNode.new
125
+ end
126
+ puts "Expected R, found: " + t.lex
127
+ raise ParseError.new
128
+ end
129
+
130
+ if t.type == :lparen then
131
+ result = Expr()
132
+
133
+ t = @scan.getToken
134
+ if t.type == :rparen then
135
+ return result
136
+ end
137
+
138
+ puts "Expected ')' found: " + t.type.to_s
139
+ raise ParseError.new
140
+ end
141
+
142
+ puts "Expected number, R, ( found: " + t.type
143
+ raise ParseError.new #"ParseError"
144
+
145
+ end
146
+ end
@@ -0,0 +1,127 @@
1
+ require 'stringio' #No se pone *.rb
2
+ require 'calcex'
3
+
4
+ class Scanner
5
+ def initialize(inStream)
6
+ @istream = inStream
7
+ @keywords = Set.new(["S","R"])
8
+ @lineCount = 1
9
+ @colCount = -1
10
+ @needToken = true
11
+ @lastToken = nil
12
+ end
13
+
14
+ def putBackToken()
15
+ @needToken = false
16
+ end
17
+
18
+ def getToken()
19
+ unless @needToken
20
+ @needToken = true
21
+ return @lastToken
22
+ end
23
+
24
+ state = 0
25
+ foundOne = false
26
+ c = @istream.getc()
27
+
28
+ if @istream.eof() then
29
+ @lastToken = Token.new(:eof,@lineCount,@colCount)
30
+ return @lastToken
31
+ end
32
+
33
+ until foundOne
34
+ @colCount = @colCount + 1
35
+ case state
36
+ when 0 #La manera de preguntar por los estados: when
37
+ lex = ""
38
+ column = @colCount
39
+ line = @lineCount
40
+ if isLetter(c) then state=1
41
+ elsif isDigit(c) then state=2
42
+ elsif c == ?+ then state = 3
43
+ elsif c == ?- then state = 4
44
+ elsif c == ?* then state = 5
45
+ elsif c == ?/ then state = 6
46
+ elsif c == ?( then state = 7
47
+ elsif c == ?) then state = 8
48
+ elsif c == ?\n then
49
+ @colCount = -1
50
+ @lineCount = @lineCount+1
51
+ elsif isWhiteSpace(c) then state = state #ignore whitespace
52
+ elsif @istream.eof() then
53
+ @foundOne = true
54
+ type = :eof
55
+ else
56
+ puts "Unrecognized Token found at line ",line," and column ",column,"\n"
57
+ raise UnrecognizedTokenException # "Unrecognized Token"
58
+ end
59
+ when 1
60
+ if isLetter(c) or isDigit(c) then state = 1
61
+ else
62
+ if @keywords.include?(lex) then
63
+ foundOne = true
64
+ type = :keyword
65
+ else
66
+ foundOne = true
67
+ type = :identifier
68
+ end
69
+ end
70
+ when 2
71
+ if isDigit(c) then state = 2
72
+ else
73
+ type = :number
74
+ foundOne = true
75
+ end
76
+ when 3
77
+ type = :add
78
+ foundOne = true
79
+ when 4
80
+ type = :sub
81
+ foundOne = true
82
+ when 5
83
+ type = :times
84
+ foundOne = true
85
+ when 6
86
+ type = :divide
87
+ foundOne = true
88
+ when 7
89
+ type = :lparen
90
+ foundOne = true
91
+ when 8
92
+ type = :rparen
93
+ foundOne = true
94
+ end
95
+
96
+ if !foundOne then
97
+ lex.concat(c)
98
+ c = @istream.getc()
99
+ end
100
+
101
+ end
102
+
103
+ @istream.ungetc(c)
104
+ @colCount = @colCount - 1
105
+ if type == :number or type == :identifier or type == :keyword then
106
+ t = LexicalToken.new(type,lex,line,column)
107
+ else
108
+ t = Token.new(type,line,column)
109
+ end
110
+
111
+ @lastToken = t
112
+ return t
113
+ end
114
+
115
+ private
116
+ def isLetter(c)
117
+ return ((?a <= c and c <= ?z) or (?A <= c and c <= ?Z))
118
+ end
119
+
120
+ def isDigit(c)
121
+ return (?0 <= c and c <= ?9)
122
+ end
123
+
124
+ def isWhiteSpace(c)
125
+ return (c == ?\ or c == ?\n or c == ?\t)
126
+ end
127
+ end
@@ -0,0 +1,20 @@
1
+ # coding: utf-8
2
+ class Token
3
+ attr_reader :type, :line, :col
4
+
5
+ def initialize(type,lineNum,colNum)
6
+ @type = type
7
+ @line = lineNum
8
+ @col = colNum
9
+ end
10
+ end
11
+
12
+ class LexicalToken < Token #Herencia simple, no se puede multiple como en c++, no se pone public tampoco
13
+ attr_reader :lex
14
+
15
+ def initialize(type,lex,lineNum,colNum) #constructor que dentro de sí, llama al constructor de la clase padre mediante el super.
16
+ super(type,lineNum,colNum)
17
+
18
+ @lex = lex
19
+ end
20
+ end
metadata ADDED
@@ -0,0 +1,51 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: calc_jzapat80
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Kent D. Lee - Juan Francisco Cardona Mc - Jonathan Stiven Zapata
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-11-12 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: An calculator implementation on ruby
14
+ email: fcardona@eafit.edu.co - jzapat80@eafit.edu.co
15
+ executables:
16
+ - calc
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - bin/calc
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.7
48
+ signing_key:
49
+ specification_version: 4
50
+ summary: Another calculator in ruby
51
+ test_files: []