calc_danmontoya 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1ad2c711ad4275c39aa71213e191e76681530150
4
+ data.tar.gz: 934c616d4b0e1d9730e9b989a2aec5149ba6e634
5
+ SHA512:
6
+ metadata.gz: 6be7ee87389d45fbea4c8276298678b7c0ff1f25cefa6053376e7a5b0c96502ee9d6f677d2c819f3124f617711fd9a3a38c061d18e1eb4095d8279470906321f
7
+ data.tar.gz: 220c57f0726515fd6dcc567522d3e7f4e9d0ead994cf57fbef5affeeb9e0d0ca010c3342dbd622000907be03831aace1c81ee4630b4629c4bc2994e9e2481986
data/bin/calc ADDED
@@ -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
data/lib/ast.rb ADDED
@@ -0,0 +1,102 @@
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 ModNode < BinaryNode
61
+ def initialize(left, right)
62
+ super(left, right)
63
+ end
64
+ def evaluate()
65
+ return @left.evaluate() % @right.evaluate()
66
+ end
67
+ end
68
+
69
+ class EmpowerNode < BinaryNode
70
+ def initialize(left,rigth)
71
+ super(left,right)
72
+ end
73
+ def evaluate
74
+ return @left.evaluate() ** @right.evaluate()
75
+ end
76
+ end
77
+
78
+ class StoreNode < UnaryNode
79
+ def initialize(subTree)
80
+ super(subTree)
81
+ end
82
+
83
+ def evaluate()
84
+ $calc.memory = subTree.evaluate()
85
+ end
86
+ end
87
+
88
+ class NumNode
89
+ def initialize(num)
90
+ @num = num
91
+ end
92
+
93
+ def evaluate()
94
+ return @num
95
+ end
96
+ end
97
+
98
+ class RecallNode
99
+ def evaluate
100
+ $calc.memory
101
+ end
102
+ end
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,140 @@
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
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
+ 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
+
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
+ RestTerm(Storable())
64
+ end
65
+
66
+ def RestTerm(e)
67
+
68
+ t=@scan.getToken
69
+ if t.type == :times then
70
+ t=@scan.getToken
71
+ if t.type == :times then
72
+ return RestExpr(EmpowerNode.new(e,Storable()))
73
+ else
74
+ return RestExpr(TimesNode.new(e,Storable()))
75
+ end
76
+ end
77
+
78
+ if t.type == :divide then
79
+ return RestExpr(DivideNode.new(e,Storable()))
80
+ end
81
+
82
+ if t.type == :mod then
83
+ return RestExpr(ModNode.new(e,Storable()))
84
+ end
85
+
86
+ # if t.type == :empower then
87
+ # return RestExpr(EmpowerNode.new(e,Storable()))
88
+ # end
89
+
90
+ @scan.putBackToken
91
+ return e
92
+
93
+ end
94
+
95
+ def Storable
96
+ result = Factor()
97
+ t = @scan.getToken
98
+ if t.type == :keyword then
99
+ if t.lex == 'S' then
100
+ return StoreNode.new(result)
101
+ end
102
+
103
+ puts "Expected S found: #{t.lex} at line: #{t.line} col: #{t.col}"
104
+
105
+ raise ParseError.new
106
+ end
107
+ @scan.putBackToken
108
+ return result
109
+ end
110
+
111
+ def Factor
112
+
113
+ t = @scan.getToken
114
+
115
+ if t.type == :number then
116
+ return NumNode.new t.lex.to_i
117
+ end
118
+
119
+ if t.type = :keyword then
120
+ if t.lex == 'R' then
121
+ return RecallNode.new
122
+ end
123
+ puts "Parser Error: expected R found: #{t.lex} at line_ #{t.line} col: #{t.col}"
124
+ raise ParseError.new
125
+ end
126
+
127
+ if t.type = :lparen then
128
+ result = Expr
129
+ t = @scan.getToken
130
+ if t.type = :rparen then
131
+ return result
132
+ end
133
+ puts "Parser Error: expected ')' found: #{t.lex} at line: #{t.line} col: #{t.col}"
134
+ raise ParseError.new
135
+ end
136
+ print "Parser Error: expected number, R, ( found: #{t.type} at line #{t.line} col: #{t.col}"
137
+ raise ParseError.new
138
+ end
139
+
140
+ end
data/lib/scanner.rb ADDED
@@ -0,0 +1,135 @@
1
+ require 'stringio'
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 #if !@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 += 1
35
+ case state
36
+ when 0
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 == ?% then state = 9
49
+ elsif c == '\n' then
50
+ @colCount = -1
51
+ @lineCount = @lineCount+1
52
+ elsif isWhiteSpace(c) then state = state #ignore whitespace
53
+ elsif @istream.eof() then
54
+ @foundOne = true
55
+ type = :eof
56
+ else
57
+ puts "Unrecognized Token found at line ",line," and column ",column,"\n"
58
+ raise UnrecognizedTokenException # "Unrecognized Token"
59
+ end
60
+
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
+ when 9
97
+ type = :mod
98
+ foundOne = true
99
+ when 10
100
+ type = :empower
101
+ foundOne = true
102
+ end
103
+
104
+ if !foundOne then
105
+ lex.concat(c)
106
+ c = @istream.getc()
107
+ end
108
+
109
+ end
110
+
111
+ @istream.ungetc(c)
112
+ @colCount = @colCount - 1
113
+ if type == :number or type == :identifier or type == :keyword then
114
+ t = LexicalToken.new(type,lex,line,column)
115
+ else
116
+ t = Token.new(type,line,column)
117
+ end
118
+
119
+ @lastToken = t
120
+ return t
121
+ end
122
+
123
+ private
124
+ def isLetter(c)
125
+ return ((?a <= c and c <= ?z) or (?A <= c and c <= ?Z))
126
+ end
127
+
128
+ def isDigit(c)
129
+ return (?0 <= c and c <= ?9)
130
+ end
131
+
132
+ def isWhiteSpace(c)
133
+ return (c == ?\ or c == ?\n or c == ?\t)
134
+ end
135
+ 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: calc_danmontoya
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Kent D. Lee - Juan Francisco Cardona Mc - Pablo Quijano Jaramillo
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: pquijano@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: []