calc_dsalaz26 0.0.1

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: ac46daeb4898891060f235bfc94e7a844ea7e3dc
4
+ data.tar.gz: 8d3be5804700679b7002e7ca3ed2a72885e1669f
5
+ SHA512:
6
+ metadata.gz: d33ef502efc60c49b39fc3b0231662fc2239b04f40312911f940fec9015428e96784d97b800bd6980da4d356c218f1092100c505036f45e12dab05f0a8395d6a
7
+ data.tar.gz: 05f7847748a297fe55cf4b94d886bda041e62b2c6a32aba7290f7dc1537c84461e1e0a51a32ef5b505f0972080ef1711d39029b26216e0f4d10c59852d95104e
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
+ return @left.evaluate() + @right.evaluate()
27
+ end
28
+ end
29
+
30
+ class TimesNode < 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 DivideNode < 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 SubNode < 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 StoreNode < UnaryNode
61
+ def initialize(subTree)
62
+ super(subTree)
63
+ end
64
+
65
+ def evaluate()
66
+ $calc.memory = subTree.evaluate()
67
+ end
68
+ end
69
+
70
+ class NumNode
71
+ def initialize(num)
72
+ @num = num
73
+ end
74
+
75
+ def evaluate()
76
+ return @num
77
+ end
78
+ end
79
+
80
+ class RecallNode
81
+ def evaluate()
82
+ $calc.memory
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,121 @@
1
+ require 'ast'
2
+ require 'stringio'
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
+ 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
+ return e
47
+ end
48
+
49
+ def Term
50
+ return RestTerm(Storable())
51
+ end
52
+
53
+ def RestTerm(e)
54
+ t = @scan.getToken()
55
+
56
+ if t.type == :times then
57
+ return RestTerm(TimesNode.new(e, Storable))
58
+ end
59
+
60
+ if t.type == :divide then
61
+ return Resterm(DivideNode.new(e, Storable))
62
+ end
63
+
64
+ if t.type == :mod then
65
+ return Resterm(ModNode.new(e, Storable))
66
+ end
67
+
68
+ @scan.putBackToken()
69
+
70
+ e
71
+
72
+ end
73
+
74
+ def Storable
75
+
76
+ result=Factor()
77
+
78
+ t = @scan.getToken
79
+
80
+ if t.type == :keyword then
81
+ if t.lex == "S" then
82
+ return StoreNode.new(result)
83
+ else
84
+ puts "*Expected s found: #{t.lex} at line: #{t.line} col: #{t.col}"
85
+ raise ParserError.new # "Parse Error"
86
+ end
87
+ end
88
+ @scan.putBackToken
89
+
90
+ result
91
+
92
+ end
93
+
94
+ def Factor
95
+ t = @scan.getToken
96
+ if t.type == :number then
97
+ return NumNode.new(t.lex.to_i)
98
+ end
99
+ if t.type == :keyword then
100
+ if t.lex == "R" then
101
+ return RecallNode.new
102
+ end
103
+ else
104
+ puts "*Expected s found: #{t.lex} at line: #{t.line} col: #{t.col}"
105
+ raise ParserError.new # "Parse Error"
106
+ end
107
+ if t.type == :lparen then
108
+ result = Expr()
109
+ t = @scan.getToken
110
+ if t.type == :rparen then
111
+ return result
112
+ end
113
+ puts "Parser Error: expected ) found: #{t.lex}"
114
+ puts "at line: #{t.line} col: #{t.col}"
115
+ raise ParseError.new
116
+ end
117
+
118
+ puts "Factor not implemented"
119
+ raise ParserError.new # "Parse Error"
120
+ end
121
+ end
data/lib/scanner.rb ADDED
@@ -0,0 +1,128 @@
1
+ require 'stringio'
2
+ require 'calcex'
3
+
4
+ class Scanner
5
+ def initialize(inStream)
6
+ @istream = inStream
7
+ @keywords = Set.new(%w{S R})
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
+ def getToken()
20
+ if !@needToken # = unless @neddToken
21
+ @needToken = true
22
+ return @lastToken
23
+ end
24
+
25
+ state = 0
26
+ foundOne = false
27
+ c = @istream.getc()
28
+
29
+ if @istream.eof? then
30
+ @lastToken = Token.new(:eof,@lineCount,@colCount)
31
+ return @lastToken
32
+ end
33
+
34
+ while !foundOne
35
+ @colCount = @colCount + 1
36
+ case state
37
+ when 0
38
+ lex = ""
39
+ column = @colCount
40
+ line = @lineCount
41
+ if isLetter(c) then state=1
42
+ elsif isDigit(c) then state=2
43
+ elsif c == ?+ then state = 3
44
+ elsif c == ?- then state = 4
45
+ elsif c == ?* then state = 5
46
+ elsif c == ?/ then state = 6
47
+ elsif c == ?( then state = 7
48
+ elsif c == ?) then state = 8
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
+ when 1
61
+ if isLetter(c) or isDigit(c) then state = 1
62
+ else
63
+ if @keywords.include?(lex) then
64
+ foundOne = true
65
+ type = :keyword
66
+ else
67
+ foundOne = true
68
+ type = :identifier
69
+ end
70
+ end
71
+ when 2
72
+ if isDigit(c) then state = 2
73
+ else
74
+ type = :number
75
+ foundOne = true
76
+ end
77
+ when 3
78
+ type = :add
79
+ foundOne = true
80
+ when 4
81
+ type = :sub
82
+ foundOne = true
83
+ when 5
84
+ type = :times
85
+ foundOne = true
86
+ when 6
87
+ type = :divide
88
+ foundOne = true
89
+ when 7
90
+ type = :lparen
91
+ foundOne = true
92
+ when 8
93
+ type = :rparen
94
+ foundOne = true
95
+ end
96
+
97
+ if !foundOne then
98
+ lex.concat(c)
99
+ c = @istream.getc()
100
+ end
101
+
102
+ end
103
+
104
+ @istream.ungetc(c)
105
+ @colCount = @colCount - 1
106
+ if type == :number or type == :identifier or type == :keyword then
107
+ t = LexicalToken.new(type,lex,line,column)
108
+ else
109
+ t = Token.new(type,line,column)
110
+ end
111
+
112
+ @lastToken = t
113
+ return t
114
+ end
115
+
116
+ private
117
+ def isLetter(c)
118
+ return ((?a <= c and c <= ?z) or (?A <= c and c <= ?Z))
119
+ end
120
+
121
+ def isDigit(c)
122
+ return (?0 <= c and c <= ?9)
123
+ end
124
+
125
+ def isWhiteSpace(c)
126
+ return (c == ?\ or c == ?\n or c == ?\t)
127
+ end
128
+ 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_dsalaz26
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Kent D. Lee - Juan Francisco Cardona Mc - Diego Salazar Noreña
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: dsalaz26@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: []