calc_abedoy19 0.2.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: 7a41a7e7f96c5f63b72e59f619c8766d13c75f21
4
+ data.tar.gz: 790b3b69d90192755d48cb3bf7adb3ea363282f9
5
+ SHA512:
6
+ metadata.gz: a608fcbbbc1ae85fe6e91259da1d01a3afeabc44f2fe2cc83b6ce22c828845f7133bac57fa828a5cf62cd6484fb2ab78279294f775c1b6964d3a5e7c822dea87
7
+ data.tar.gz: 272618ff6d92eedfa00374776b4d58e9a47fad2e393d1afc3daf1713e0468775439729fc47dd20a591e7f78b32f10f24107d526890f83a8d604a30543b1641c3
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,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
+ 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
+ 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
+ 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
+ left.evaluate / right.evaluate
57
+ end
58
+ end
59
+
60
+ class StoreNode < UnaryNode
61
+ def initialize(sub)
62
+ super(sub)
63
+ end
64
+
65
+ def evaluate
66
+ $calc.memory = subTree.evaluate
67
+ end
68
+ end
69
+
70
+ class RecallNode
71
+ def evaluate
72
+ $calc.memory
73
+ end
74
+ end
75
+
76
+ class NumNode
77
+ def initialize(num)
78
+ @num = num
79
+ end
80
+
81
+ def evaluate
82
+ @num
83
+ end
84
+ 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,130 @@
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
+ Prog() #No requiere return.
14
+ end
15
+
16
+ private
17
+ def Prog()
18
+ result = Expr()
19
+ t = @scan.getToken #Si una función no requiere parámetros no es necesario ().
20
+
21
+ if t.type != :eof then
22
+ print "Expected EOF. Found ", t.type, ".\n"
23
+ raise ParseError.new
24
+ end
25
+
26
+ result #Está retornando el resultado.
27
+ end
28
+
29
+ def Expr()
30
+ return 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
+ 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
+ t = @scan.getToken
68
+
69
+ if t.type == :times then
70
+ return RestTerm(TimesNode.new(e,Storable()))
71
+ end
72
+
73
+ if t.type == :divide then
74
+ return RestTerm(DivideNode.new(e,Storable()))
75
+ end
76
+
77
+ @scan.putBackToken
78
+
79
+ e
80
+ end
81
+
82
+ def Storable
83
+ result = Factor()
84
+ t = @scan.getToken
85
+
86
+ if t.type == :keyword then
87
+ if t.lex == "S" then
88
+ return StoreNode.new(result)
89
+ end
90
+
91
+ print "Expected S found #{t.lex} "
92
+ puts " at line: #{t.line} col: #{t.col}"
93
+ raise ParseError.new
94
+ end
95
+
96
+ @scan.putBackToken
97
+ result
98
+ end
99
+
100
+ def Factor
101
+ t = @scan.getToken
102
+
103
+ if t.type == :number then
104
+ return NumNode.new(t.lex.to_i)
105
+ end
106
+
107
+ if t.type == :keyword then
108
+ if t.lex == "R" then
109
+ return RecallNode.new
110
+ end
111
+
112
+ puts "Parse Error"
113
+ raise ParseError.new
114
+ end
115
+
116
+ if t.type == :lparen then
117
+ result = Expr()
118
+ t = @scan.getToken
119
+ if t.type == :rparen then
120
+ return result
121
+ end
122
+
123
+ puts "Error"
124
+ raise ParseError.new
125
+ end
126
+
127
+ puts "Error"
128
+ raise ParseError.new
129
+ end
130
+ end
data/lib/scanner.rb ADDED
@@ -0,0 +1,127 @@
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
+ 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
+ while !foundOne
34
+ @colCount = @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 == ?\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
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_abedoy19
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Kent D. Lee - Ana María Bedoya Hernández - Juan Francisco Cardona Mc
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-11-13 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: An calculator implementation on ruby
14
+ email: abedoy19@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: []