calc_pquijano 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: 4c187f503e20ac0f9b2ea03ab0eb669b0b6deff5
4
+ data.tar.gz: b113a238d3e19ff85f4b41354ec0e02e6173f58e
5
+ SHA512:
6
+ metadata.gz: ac65340c8b36d3074db038ef8f67bd5281c6fd2ea692b255b1503c5a733349267c1cb2fa51a9b3b01a76a2c395a2272e51a57220776e3b49235175ba597170b7
7
+ data.tar.gz: 692b97c80d88f8ec67d55fc831c222cc8a29bc1cfc476504c35700c19d19378bff52166f29c3f023bf78ba4ebccc833f86b412cf9c29fcaff419c6d814817a36
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,107 @@
1
+ require 'set'
2
+ require 'bigdecimal'
3
+ require 'bigdecimal/math'
4
+
5
+ class BinaryNode
6
+ attr_reader :left, :right
7
+
8
+ def initialize(left,right)
9
+ @left = left
10
+ @right = right
11
+ end
12
+ end
13
+
14
+ class UnaryNode
15
+ attr_reader :subTree
16
+
17
+ def initialize(subTree)
18
+ @subTree = subTree
19
+ end
20
+ end
21
+
22
+ class AddNode < BinaryNode
23
+ def initialize(left, right)
24
+ super(left,right)
25
+ end
26
+
27
+ def evaluate()
28
+ return @left.evaluate() + @right.evaluate()
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 ModuleNode < BinaryNode
63
+ def initialize(left, right)
64
+ super(left,right)
65
+ end
66
+
67
+ def evaluate()
68
+ return @left.evaluate() % @right.evaluate()
69
+ end
70
+ end
71
+
72
+ class PowerNode < BinaryNode
73
+ def initialize(left, right)
74
+ super(left,right)
75
+ end
76
+
77
+ def evaluate()
78
+ return @left.evaluate() ** @right.evaluate()
79
+ end
80
+ end
81
+
82
+ class StoreNode < UnaryNode
83
+ def initialize(subTree)
84
+ super(subTree)
85
+ end
86
+
87
+ def evaluate()
88
+ $calc.memory = subTree.evaluate()
89
+ end
90
+ end
91
+
92
+ class NumNode
93
+ def initialize(num)
94
+ @num = num
95
+ end
96
+
97
+ def evaluate()
98
+ return @num
99
+ end
100
+ end
101
+
102
+ class RecallNode
103
+ def evaluate
104
+ $calc.memory
105
+ end
106
+ end
107
+
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 '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
+ @scan.putBackToken
44
+
45
+ e
46
+ end
47
+
48
+ def Term
49
+ RestTerm(Storable())
50
+ end
51
+
52
+ def RestTerm(e)
53
+ t = @scan.getToken
54
+
55
+ if t.type == :divide then
56
+ return RestExpr(DivideNode.new(e,Storable()))
57
+ end
58
+
59
+ if t.type == :times then
60
+ t = @scan.getToken
61
+ if t.type == :times then
62
+ return RestExpr(PowerNode.new(e,Storable()))
63
+ end
64
+ @scan.putBackToken
65
+ return RestExpr(TimesNode.new(e,Storable()))
66
+ end
67
+
68
+ if t.type == :module then
69
+ return RestExpr(ModuleNode.new(e,Storable()))
70
+ end
71
+
72
+ @scan.putBackToken
73
+
74
+ e
75
+ end
76
+
77
+ def Storable
78
+ result = Factor()
79
+ t = @scan.getToken
80
+
81
+ if t.type == :keyword then
82
+ if t.lex == 'S' then
83
+ return StoreNode.new(result)
84
+ end
85
+ puts "Expected S found: #{t.lex} at line: #{t.line} col: #{t.col}"
86
+ raise ParseError.new
87
+ end
88
+
89
+ @scan.putBackToken
90
+ result
91
+
92
+ end
93
+
94
+ def Factor()
95
+ t = @scan.getToken
96
+
97
+ if t.type == :number then
98
+ return NumNode.new(t.lex.to_i)
99
+ end
100
+
101
+ if t.type == :keyword then
102
+ if t.lex == 'R' then
103
+ return RecallNode.new
104
+ end
105
+ puts "Expected R found: #{t.lex} at line: #{t.line} col: #{t.col}"
106
+ raise ParseError.new
107
+ end
108
+
109
+ if t.type == :lparen then
110
+ result = Expr()
111
+ t = @scan.getToken
112
+ if type == :rparen then
113
+ result
114
+ end
115
+ puts "Parser Error: expected ) found #{t.lex} at line: #{t.line} col: #{t.col}"
116
+ raise ParseError.new
117
+ end
118
+ puts "Parser Error: expected number, R, ( found #{t.type} at line: #{t.line} col: #{t.col}"
119
+ raise ParseError.new
120
+ end
121
+ end
data/lib/scanner.rb ADDED
@@ -0,0 +1,131 @@
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
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
+ 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
+ when 9
96
+ type = :module
97
+ foundOne = true
98
+ end
99
+
100
+ if !foundOne then
101
+ lex.concat(c)
102
+ c = @istream.getc()
103
+ end
104
+
105
+ end
106
+
107
+ @istream.ungetc(c)
108
+ @colCount = @colCount - 1
109
+ if type == :number or type == :identifier or type == :keyword then
110
+ t = LexicalToken.new(type,lex,line,column)
111
+ else
112
+ t = Token.new(type,line,column)
113
+ end
114
+
115
+ @lastToken = t
116
+ return t
117
+ end
118
+
119
+ private
120
+ def isLetter(c)
121
+ return ((?a <= c and c <= ?z) or (?A <= c and c <= ?Z))
122
+ end
123
+
124
+ def isDigit(c)
125
+ return (?0 <= c and c <= ?9)
126
+ end
127
+
128
+ def isWhiteSpace(c)
129
+ return (c == ?\ or c == ?\n or c == ?\t)
130
+ end
131
+ 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_pquijano
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: []