calc_esilvac 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 16593a5279ec84214a8d4d9f23ff1ce276bb3e6d
4
+ data.tar.gz: b6931f4380cabfc14d81df6103493e73529728f1
5
+ SHA512:
6
+ metadata.gz: 8e3c90af9bff0d99e2407618925757148442edb17ee714a0726756cdac51cfd53c26002cd1a6c22a22c8c634419fd192fd0ac0bcd51e55462298c5e169aedbcd
7
+ data.tar.gz: 684e318d602daede81648d7c44b5b042dd60b9e12e3e11d46c4c6a71ab732e6c913eab1975f93df5b3cba8019343f8f4d4ebdd51262c0e392bf4a29dc841e262
data/bin/calc ADDED
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'calculator'
4
+ require 'calcex'
5
+
6
+ fichero = true
7
+ oper=:none
8
+ priori=:none
9
+
10
+ $calc = Calculator.new()
11
+ $calc.EnvVar
12
+
13
+ ARGV.each do |v|
14
+ if v.include? ?. then
15
+ oper=:fich
16
+ end
17
+
18
+ case v
19
+ when "-e"
20
+ oper=:e
21
+ when "-v"
22
+ if oper==:none then
23
+ oper=:v
24
+ end
25
+ else
26
+ case oper
27
+ when :e
28
+ $calc.ArgPri(v)
29
+ when :v
30
+ $calc.ArgNoPri(v)
31
+ when :fich
32
+ fichero = false
33
+ $calc.eval(v)
34
+ end
35
+ end
36
+ end
37
+
38
+ if fichero then
39
+ $stdout.print "> "
40
+ end
41
+
42
+ while fichero && text = $stdin.gets do
43
+
44
+ begin
45
+ $calc.eval(text).to_s
46
+ rescue ParseError
47
+ puts "*parse error"
48
+ rescue UnrecognizedTokenException
49
+ puts "UnrecognizedTokenException"
50
+ rescue
51
+ puts "Unkown exception"
52
+ end
53
+ $stdout.print "> "
54
+ end
55
+
data/lib/ast.rb ADDED
@@ -0,0 +1,149 @@
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
+
41
+ class StoreNode < UnaryNode
42
+ def initialize(subTree)
43
+ super(subTree)
44
+ end
45
+
46
+ def evaluate
47
+ $calc.memory = subTree.evaluate
48
+ end
49
+ end
50
+
51
+ class RecallNode
52
+ def evaluate
53
+ $calc.memory
54
+ end
55
+ end
56
+
57
+ class CleanNode
58
+ def evaluate
59
+ $calc.memory = 0
60
+ end
61
+ end
62
+
63
+
64
+ class MinusNode < UnaryNode
65
+ def initialize(subTree)
66
+ super(subTree)
67
+ end
68
+
69
+ def evaluate
70
+ val = subTree.evaluate.to_i
71
+ $calc.memory -= val
72
+ end
73
+ end
74
+
75
+ class PlusNode < UnaryNode
76
+ def initialize(subTree)
77
+ super(subTree)
78
+ end
79
+
80
+ def evaluate
81
+ val = subTree.evaluate
82
+ $calc.memory += val
83
+ end
84
+ end
85
+
86
+ class NumNode
87
+ def initialize(num)
88
+ @num = num
89
+ end
90
+
91
+ def evaluate()
92
+ @num
93
+ end
94
+ end
95
+
96
+
97
+ class TimesNode < BinaryNode
98
+ def initialize(left, right)
99
+ super(left,right)
100
+ end
101
+
102
+ def evaluate()
103
+ @left.evaluate() * @right.evaluate()
104
+ end
105
+ end
106
+
107
+
108
+ class DivideNode < BinaryNode
109
+ def initialize(left, right)
110
+ super(left,right)
111
+ end
112
+
113
+ def evaluate
114
+ @left.evaluate() / @right.evaluate()
115
+ end
116
+ end
117
+
118
+
119
+ class ModuleNode < BinaryNode
120
+ def initialize(left, right)
121
+ super(left,right)
122
+ end
123
+
124
+ def evaluate
125
+ @left.evaluate() % @right.evaluate()
126
+ end
127
+ end
128
+
129
+ class GuardarNode
130
+ def initialize(var,val)
131
+ @var = var
132
+ @val = val
133
+ end
134
+
135
+ def evaluate
136
+ $calc.guardar(@var,@val)
137
+ return @val
138
+ end
139
+ end
140
+
141
+ class LlamarNode
142
+ def initialize(var)
143
+ @var = var
144
+ end
145
+
146
+ def evaluate
147
+ $calc.llamar(@var)
148
+ end
149
+ 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,70 @@
1
+ require 'parser'
2
+ require 'ast'
3
+
4
+ class Calculator
5
+ attr_accessor :memory
6
+
7
+ def initialize()
8
+ @memory = 0
9
+ @map = Hash.new(0)
10
+ @vblis = ""
11
+ end
12
+
13
+ def eval(expr)
14
+ parser = Parser.new(expr)
15
+ parser.parse()
16
+ end
17
+
18
+ def guardar(var,val)
19
+ @map[var] = val
20
+ @vblis += var + " <- " + val.to_s + ", "
21
+ end
22
+
23
+ def guardarAE(var,val)
24
+ @map[var] = val
25
+ end
26
+
27
+ def llamar(var)
28
+ return @map[var]
29
+ end
30
+
31
+ def EnvVar
32
+ ENV.each do |k,v|
33
+ if k.match("CALCVAR") then
34
+ var = k[7,k.length]
35
+ val = v.to_i
36
+ $calc.guardarAE(var,val)
37
+ end
38
+ end
39
+ end
40
+
41
+ def ArgPri(varia)
42
+ pr = varia.index('=')
43
+ if pr != nil then
44
+ var = varia[0,pr]
45
+ if @map.has_key?(var) == false then
46
+ val = varia[pr+1,varia.length].to_i
47
+ $calc.guardarAE(var,val)
48
+ end
49
+ end
50
+ end
51
+
52
+ def ArgNoPri(varia)
53
+ pr = varia.index('=')
54
+ if pr != nil then
55
+ var = varia[0,pr]
56
+ val = varia[pr+1,varia.length].to_i
57
+ $calc.guardarAE(var,val)
58
+ end
59
+ end
60
+
61
+ def imprimir(line,result)
62
+ if line.include? "=" then
63
+ copva = @vblis.chop.chop
64
+ puts "=> " + result.to_s + " [" + copva + "]"
65
+ @vblis = ""
66
+ else
67
+ puts "=> " + result.to_s
68
+ end
69
+ end
70
+ end
data/lib/parser.rb ADDED
@@ -0,0 +1,169 @@
1
+ require 'ast'
2
+ require 'scanner'
3
+ require 'token'
4
+ require 'calcex'
5
+
6
+ class Parser
7
+ def initialize(expr)
8
+ @fichi = expr
9
+ @scan = Scanner.new()
10
+ end
11
+
12
+ def parse()
13
+ Prog()
14
+ end
15
+
16
+ private
17
+ def Prog()
18
+ ListExpr()
19
+ end
20
+
21
+ def ListExpr()
22
+ if @fichi.include? ?. then
23
+ File.open(@fichi) do |f|
24
+ while line = f.gets
25
+ @scan.CogeLinea(line)
26
+ result = Expr()
27
+ t = @scan.getToken()
28
+ $calc.imprimir(line, result.evaluate())
29
+ if t.type != :eof then
30
+ raise ParseError.new
31
+ end
32
+ end
33
+ end
34
+ else
35
+ @scan.CogeLinea(@fichi)
36
+ result = Expr()
37
+ t = @scan.getToken()
38
+ $calc.imprimir(@fichi, result.evaluate())
39
+ if t.type != :eof then
40
+ raise ParseError.new
41
+ end
42
+ end
43
+ end
44
+
45
+ def Expr()
46
+ return RestExpr(Term())
47
+ end
48
+
49
+ def RestExpr(e)
50
+ t = @scan.getToken()
51
+
52
+ if t.type == :add then
53
+ return RestExpr(AddNode.new(e,Term()))
54
+ end
55
+
56
+ if t.type == :sub then
57
+ return RestExpr(SubNode.new(e,Term()))
58
+ end
59
+
60
+ @scan.putBackToken()
61
+
62
+ return e
63
+ end
64
+
65
+ def Term()
66
+ RestTerm(Storable())
67
+ end
68
+
69
+ def RestTerm(e)
70
+ t = @scan.getToken
71
+
72
+ if t.type == :times then
73
+ return RestTerm(TimesNode.new(e,Storable()))
74
+ end
75
+
76
+ if t.type == :divide then
77
+ return RestTerm(DivideNode.new(e,Storable()))
78
+ end
79
+
80
+ if t.type == :module then
81
+ return RestTerm(ModuleNode.new(e,Storable()))
82
+ end
83
+
84
+ @scan.putBackToken
85
+
86
+ return e
87
+
88
+ end
89
+
90
+ def Storable()
91
+ MemOperation(Factor())
92
+ end
93
+
94
+ def MemOperation(e)
95
+
96
+ t = @scan.getToken
97
+ if (t.type == :keyword) then
98
+ if (t.lex == "S") then
99
+ return StoreNode.new(e)
100
+ end
101
+ if (t.lex == "P") then
102
+ return PlusNode.new(e)
103
+ end
104
+ if (t.lex == "M") then
105
+ return MinusNode.new(e)
106
+ end
107
+ raise ParseError.new
108
+ end
109
+
110
+ @scan.putBackToken
111
+ return e
112
+ end
113
+
114
+
115
+ def Factor()
116
+
117
+ t = @scan.getToken
118
+
119
+ if t.type == :number then
120
+ return NumNode.new(t.lex.to_i)
121
+ end
122
+
123
+ if t.type == :keyword then
124
+ if t.lex == "R" then
125
+ return RecallNode.new
126
+ end
127
+ if t.lex == "C" then
128
+ return CleanNode.new
129
+ end
130
+
131
+ raise ParseError.new
132
+ end
133
+
134
+ if t.type == :identifier then
135
+ @scan.putBackToken
136
+ return Assignable()
137
+ end
138
+
139
+ if t.type == :lparen then
140
+ result = Expr()
141
+
142
+ t = @scan.getToken
143
+
144
+ if t.type == :rparen then
145
+ return result
146
+ end
147
+ raise ParseError.new
148
+ end
149
+ raise ParseError.new
150
+ end
151
+ end
152
+
153
+ def Assignable()
154
+ t = @scan.getToken
155
+ var = t.lex
156
+ Assign(var)
157
+ end
158
+
159
+ def Assign(var)
160
+ t = @scan.getToken
161
+
162
+ if t.type == :equ then
163
+ val = Expr().evaluate().to_i
164
+ return GuardarNode.new(var,val)
165
+ else
166
+ @scan.putBackToken
167
+ return LlamarNode.new(var)
168
+ end
169
+ end
data/lib/scanner.rb ADDED
@@ -0,0 +1,142 @@
1
+ require 'stringio'
2
+ require 'calcex'
3
+
4
+ class Scanner
5
+ def initialize()
6
+ @istream = StringIO.new("")
7
+ @keywords = Set.new(["S","R","M","P","C"])
8
+ @lineCount = 1
9
+ @colCount = -1
10
+ @needToken = true
11
+ @lastToken = nil
12
+ end
13
+ def CogeLinea(line)
14
+ @istream = StringIO.new(line)
15
+ end
16
+
17
+ def putBackToken
18
+ @needToken = false
19
+ end
20
+
21
+ def getToken
22
+ unless @needToken
23
+ @needToken = true
24
+ return @lastToken
25
+ end
26
+
27
+ state = 0
28
+ foundOne = false
29
+ c = @istream.getc()
30
+
31
+ if @istream.eof() then
32
+ @lastToken = Token.new(:eof,@lineCount,@colCount)
33
+ return @lastToken
34
+ end
35
+
36
+ until foundOne
37
+ @colCount = @colCount + 1
38
+ case state
39
+ when 0
40
+ lex = ""
41
+ column = @colCount
42
+ line = @lineCount
43
+ if isLetter(c) then state=1
44
+ elsif isDigit(c) then state=2
45
+ elsif c == ?+ then state = 3
46
+ elsif c == ?- then state = 4
47
+ elsif c == ?* then state = 5
48
+ elsif c == ?/ then state = 6
49
+ elsif c == ?( then state = 7
50
+ elsif c == ?) then state = 8
51
+ elsif c == ?% then state = 9
52
+ elsif c == ?= then state = 10
53
+ elsif c == ?\n then
54
+ @colCount = -1
55
+ @lineCount = @lineCount+1
56
+ elsif isWhiteSpace(c) then state = state
57
+ elsif @istream.eof() then
58
+ @foundOne = true
59
+ type = :eof
60
+ else
61
+ raise UnrecognizedTokenException
62
+ end
63
+ when 1
64
+ if isLetter(c) or isDigit(c) then state = 1
65
+ else
66
+ if @keywords.include?(lex) then
67
+ foundOne = true
68
+ type = :keyword
69
+ else
70
+ foundOne = true
71
+ type = :identifier
72
+ end
73
+ end
74
+ when 2
75
+ if isDigit(c) then state = 2
76
+ else
77
+ type = :number
78
+ foundOne = true
79
+ end
80
+ when 3
81
+ type = :add
82
+ foundOne = true
83
+ when 4
84
+ type = :sub
85
+ foundOne = true
86
+ when 5
87
+ type = :times
88
+ foundOne = true
89
+ when 6
90
+ type = :divide
91
+ foundOne = true
92
+ when 7
93
+ type = :lparen
94
+ foundOne = true
95
+ when 8
96
+ type = :rparen
97
+ foundOne = true
98
+ when 9
99
+ type = :module
100
+ foundOne = true
101
+ when 10
102
+ type = :equ
103
+ foundOne = true
104
+ end
105
+
106
+
107
+ if !foundOne then
108
+ lex.concat(c)
109
+ if @istream.eof() and state == 0 then
110
+ @lastToken = Token.new(:eof,@lineCount,@colCount)
111
+ return @lastToken
112
+ end
113
+ c = @istream.getc()
114
+ end
115
+
116
+ end
117
+
118
+ @istream.ungetc(c)
119
+ @colCount = @colCount - 1
120
+ if type == :number or type == :identifier or type == :keyword then
121
+ t = LexicalToken.new(type,lex,line,column)
122
+ else
123
+ t = Token.new(type,line,column)
124
+ end
125
+
126
+ @lastToken = t
127
+ return t
128
+ end
129
+
130
+ private
131
+ def isLetter(c)
132
+ return ((?a <= c and c <= ?z) or (?A <= c and c <= ?Z))
133
+ end
134
+
135
+ def isDigit(c)
136
+ return (?0 <= c and c <= ?9)
137
+ end
138
+
139
+ def isWhiteSpace(c)
140
+ return (c == ?\ or c == ?\n or c == ?\t)
141
+ end
142
+ 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_esilvac
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Kent D. Lee - Juan Francisco Cardona Mc - Esteban Silva
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: fcardona@eafit.edu.co - esilvac@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.2.2
48
+ signing_key:
49
+ specification_version: 4
50
+ summary: Another calculator in ruby
51
+ test_files: []