calc_jgomez88 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 +7 -0
- data/bin/calc +23 -0
- data/lib/ast.rb +89 -0
- data/lib/calcex.rb +4 -0
- data/lib/calculator.rb +17 -0
- data/lib/parser.rb +138 -0
- data/lib/scanner.rb +136 -0
- data/lib/token.rb +19 -0
- metadata +51 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 61a2b5a27d01d7760aedb6ed9a2715c2dda44b8c
|
4
|
+
data.tar.gz: 844adc3e28d0d7e5e88d7dc32686127bb6133aa6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8a8d4dd2b9d7cd230d39111c4f9626645dab902c6dcfc9740a9aafa5fd22dcadf78bcc03f313ffed0faefb50ed9abe781925535e2c12eb8b3e0e7a2319c47328
|
7
|
+
data.tar.gz: ff5f8da5c84f4f1d62fc44435944d42edacb81fa3ce755c045f75e2e95416f81c569641c1c183fc21fbf2fc4c687b5f36eed26bf47f7f646179b25577d0635c1
|
data/bin/calc
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# env busca donde esta instalado ruby
|
3
|
+
# cuerpo principal de toda la calculadora
|
4
|
+
require 'rubygems'
|
5
|
+
require 'calculator'
|
6
|
+
require 'calcex'
|
7
|
+
|
8
|
+
$stdout.print "> "
|
9
|
+
$stdout.flush
|
10
|
+
|
11
|
+
text = gets
|
12
|
+
|
13
|
+
$calc = Calculator.new()
|
14
|
+
|
15
|
+
begin
|
16
|
+
puts "= " + $calc.eval(text).to_s
|
17
|
+
rescue ParseError
|
18
|
+
puts "Parse Error"
|
19
|
+
rescue UnrecognizedTokenException
|
20
|
+
puts "UnrecognizedTokenException"
|
21
|
+
rescue
|
22
|
+
puts "Unkown exception"
|
23
|
+
end
|
data/lib/ast.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
|
4
|
+
class BinaryNode
|
5
|
+
attr_reader :left, :right
|
6
|
+
|
7
|
+
def initialize(left,right) #inicializacion
|
8
|
+
@left = left
|
9
|
+
@right = right
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class UnaryNode
|
14
|
+
attr_reader :subTree
|
15
|
+
|
16
|
+
def initialize(subTree)
|
17
|
+
@subTree = subTree
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class AddNode < BinaryNode #hereda de binaryNode
|
22
|
+
def initialize(left, right)
|
23
|
+
super(left,right)
|
24
|
+
end
|
25
|
+
|
26
|
+
def evaluate()
|
27
|
+
@left.evaluate() + @right.evaluate()
|
28
|
+
#los obtiene y los evalua
|
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
|
+
|
63
|
+
class StoreNode < UnaryNode
|
64
|
+
#
|
65
|
+
def initialize(subTree)
|
66
|
+
super(subTree)
|
67
|
+
end
|
68
|
+
|
69
|
+
def evaluate
|
70
|
+
$calc.memory = subTree.evaluate()
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class RecallNode
|
75
|
+
#
|
76
|
+
def evaluate
|
77
|
+
$calc.memory
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class NumNode
|
82
|
+
def initialize(num) #
|
83
|
+
@num = num
|
84
|
+
end
|
85
|
+
|
86
|
+
def evaluate()
|
87
|
+
return @num
|
88
|
+
end
|
89
|
+
end
|
data/lib/calcex.rb
ADDED
data/lib/calculator.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'parser'
|
2
|
+
require 'ast'
|
3
|
+
|
4
|
+
class Calculator
|
5
|
+
attr_accessor :memory #lo cambiamos por accessor atttr_reader : memory
|
6
|
+
|
7
|
+
|
8
|
+
def initialize()
|
9
|
+
@memory = 0
|
10
|
+
end
|
11
|
+
|
12
|
+
def eval(expr)
|
13
|
+
parser = Parser.new(StringIO.new(expr))
|
14
|
+
ast = parser.parse()
|
15
|
+
return ast.evaluate()
|
16
|
+
end
|
17
|
+
end
|
data/lib/parser.rb
ADDED
@@ -0,0 +1,138 @@
|
|
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
|
+
#recibe un flujo de datos
|
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
|
+
#produce el sigiente token
|
21
|
+
|
22
|
+
if t.type != :eof then
|
23
|
+
print "Expected EOF. Found ", t.type, ".\n"
|
24
|
+
raise ParseError.new
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
return result
|
29
|
+
#el resultado es unaarbol abstracto sintatico
|
30
|
+
end
|
31
|
+
|
32
|
+
def Expr()
|
33
|
+
return RestExpr(Term())
|
34
|
+
end
|
35
|
+
|
36
|
+
def RestExpr(e)
|
37
|
+
t = @scan.getToken()
|
38
|
+
#leo el token
|
39
|
+
|
40
|
+
if t.type == :add then
|
41
|
+
return RestExpr(AddNode.new(e,Term()))
|
42
|
+
end
|
43
|
+
|
44
|
+
if t.type == :sub then
|
45
|
+
return RestExpr(SubNode.new(e,Term()))
|
46
|
+
end
|
47
|
+
|
48
|
+
@scan.putBackToken()
|
49
|
+
|
50
|
+
|
51
|
+
return e
|
52
|
+
end
|
53
|
+
|
54
|
+
def Term()
|
55
|
+
# Write your Term() code here. This code is just temporary
|
56
|
+
# so you can try the calculator out before finishing it.
|
57
|
+
|
58
|
+
# t = @scan.getToken()
|
59
|
+
|
60
|
+
# if t.type == :number then
|
61
|
+
# val = t.lex.to_i
|
62
|
+
# return NumNode.new(val)
|
63
|
+
# end
|
64
|
+
|
65
|
+
# puts "Term not implemented\n"
|
66
|
+
|
67
|
+
# raise ParseError.new
|
68
|
+
RestTerm(Storable())
|
69
|
+
end
|
70
|
+
|
71
|
+
def RestTerm(e)
|
72
|
+
|
73
|
+
# puts "RestTerm not implemented"
|
74
|
+
# raise ParseError.new # "Parse Error"
|
75
|
+
#lo borramos
|
76
|
+
t = @scan.getToken
|
77
|
+
if t.type == :times
|
78
|
+
return RestTerm (TimesNode.new(e, Storable()))
|
79
|
+
end
|
80
|
+
if t.type == :divide
|
81
|
+
#mira el tipo de token
|
82
|
+
return RestTerm(DivideNode.new(e, Storable()))
|
83
|
+
end
|
84
|
+
@scan.putBackToken
|
85
|
+
|
86
|
+
return e
|
87
|
+
end
|
88
|
+
|
89
|
+
def Storable()
|
90
|
+
|
91
|
+
# puts "Storable not implemented"
|
92
|
+
# raise ParseError.new # "Parse Error"
|
93
|
+
#lo borramos
|
94
|
+
result=Factor()
|
95
|
+
t = @scan.getToken
|
96
|
+
if t.type== :keyword then
|
97
|
+
if t.lex == "S" then
|
98
|
+
return StoreNode.new(result)
|
99
|
+
end
|
100
|
+
puts "Expected S found: ",t.lex
|
101
|
+
raise ParseError.new
|
102
|
+
end
|
103
|
+
@scan.putBackToken
|
104
|
+
return result
|
105
|
+
end
|
106
|
+
|
107
|
+
def Factor()
|
108
|
+
|
109
|
+
# puts "Factor not implemented"
|
110
|
+
# raise ParserError.new # "Parse Error"
|
111
|
+
#lo borramos
|
112
|
+
t = @scan.getToken
|
113
|
+
if t.type == :number then
|
114
|
+
return NumNode.new(t.lex.to_i)
|
115
|
+
#se convierte a integers
|
116
|
+
end
|
117
|
+
if t.type == :keyword then
|
118
|
+
if t.lex == "R" then
|
119
|
+
return RecallNode.new
|
120
|
+
end
|
121
|
+
puts "Expected R found: " + t.lex
|
122
|
+
raise ParseError.new
|
123
|
+
end
|
124
|
+
if t.type == :lparen then
|
125
|
+
result = Expr()
|
126
|
+
t=@scan.getToken
|
127
|
+
|
128
|
+
if t.type == :rparen then
|
129
|
+
return result
|
130
|
+
end
|
131
|
+
|
132
|
+
puts "Expected ) found: " + t.type.to_s
|
133
|
+
raise ParseError.new
|
134
|
+
end
|
135
|
+
puts "Expected number,R ( found: " + t.type.to_s
|
136
|
+
raise ParseError
|
137
|
+
end
|
138
|
+
end
|
data/lib/scanner.rb
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
#incluye los modulos(flujo de entrada de un string)
|
3
|
+
require 'calcex'
|
4
|
+
#modulo de las exepciones de ruby
|
5
|
+
|
6
|
+
class Scanner
|
7
|
+
def initialize(inStream)
|
8
|
+
@istream = inStream
|
9
|
+
#flujo de entrada
|
10
|
+
@keywords = Set.new(["S","R"])
|
11
|
+
@lineCount = 1
|
12
|
+
@colCount = -1
|
13
|
+
@needToken = true
|
14
|
+
@lastToken = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def putBackToken
|
18
|
+
#pone el valor
|
19
|
+
@needToken = false
|
20
|
+
end
|
21
|
+
|
22
|
+
def getToken
|
23
|
+
unless @needToken
|
24
|
+
@needToken = true
|
25
|
+
return @lastToken
|
26
|
+
end
|
27
|
+
|
28
|
+
state = 0
|
29
|
+
foundOne = false
|
30
|
+
c = @istream.getc()
|
31
|
+
#QUE TIPO DE CARACTER HAY
|
32
|
+
|
33
|
+
if @istream.eof() then
|
34
|
+
@lastToken = Token.new(:eof,@lineCount,@colCount)
|
35
|
+
return @lastToken
|
36
|
+
end
|
37
|
+
|
38
|
+
until foundOne
|
39
|
+
@colCount = @colCount + 1
|
40
|
+
case state
|
41
|
+
#COMIENZA CON el caracter 0
|
42
|
+
when 0
|
43
|
+
lex = ""
|
44
|
+
column = @colCount
|
45
|
+
line = @lineCount
|
46
|
+
if isLetter(c) then state=1
|
47
|
+
#pregunta de que tipo de caracter
|
48
|
+
elsif isDigit(c) then state=2
|
49
|
+
elsif c == ?+ then state = 3
|
50
|
+
elsif c == ?- then state = 4
|
51
|
+
elsif c == ?* then state = 5
|
52
|
+
elsif c == ?/ then state = 6
|
53
|
+
elsif c == ?( then state = 7
|
54
|
+
elsif c == ?) then state = 8
|
55
|
+
elsif c == ?\n then
|
56
|
+
@colCount = -1
|
57
|
+
@lineCount = @lineCount+1
|
58
|
+
elsif isWhiteSpace(c) then state = state #ignore whitespace
|
59
|
+
elsif @istream.eof() then
|
60
|
+
@foundOne = true
|
61
|
+
type = :eof
|
62
|
+
else
|
63
|
+
#lanza la exeception
|
64
|
+
puts "Unrecognized Token found at line ",line," and column ",column,"\n"
|
65
|
+
raise UnrecognizedTokenException # "Unrecognized Token"
|
66
|
+
end
|
67
|
+
when 1
|
68
|
+
if isLetter(c) or isDigit(c) then state = 1
|
69
|
+
else
|
70
|
+
if @keywords.include?(lex) then
|
71
|
+
#mira si esta inncluido el lexema
|
72
|
+
foundOne = true
|
73
|
+
type = :keyword
|
74
|
+
else
|
75
|
+
foundOne = true
|
76
|
+
type = :identifier
|
77
|
+
end
|
78
|
+
end
|
79
|
+
when 2
|
80
|
+
if isDigit(c) then state = 2
|
81
|
+
else
|
82
|
+
type = :number
|
83
|
+
foundOne = true
|
84
|
+
end
|
85
|
+
when 3
|
86
|
+
type = :add
|
87
|
+
foundOne = true
|
88
|
+
when 4
|
89
|
+
type = :sub
|
90
|
+
foundOne = true
|
91
|
+
when 5
|
92
|
+
type = :times
|
93
|
+
foundOne = true
|
94
|
+
when 6
|
95
|
+
type = :divide
|
96
|
+
foundOne = true
|
97
|
+
when 7
|
98
|
+
type = :lparen
|
99
|
+
foundOne = true
|
100
|
+
when 8
|
101
|
+
type = :rparen
|
102
|
+
foundOne = true
|
103
|
+
end
|
104
|
+
|
105
|
+
if !foundOne then
|
106
|
+
lex.concat(c)
|
107
|
+
c = @istream.getc()
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
@istream.ungetc(c)
|
113
|
+
@colCount = @colCount - 1
|
114
|
+
if type == :number or type == :identifier or type == :keyword then
|
115
|
+
t = LexicalToken.new(type,lex,line,column)
|
116
|
+
else
|
117
|
+
t = Token.new(type,line,column)
|
118
|
+
end
|
119
|
+
|
120
|
+
@lastToken = t
|
121
|
+
return t
|
122
|
+
end
|
123
|
+
#todoso los tributos son protegidos y los metodos pueden ser protegido o privado
|
124
|
+
private
|
125
|
+
def isLetter(c)
|
126
|
+
return ((?a <= c and c <= ?z) or (?A <= c and c <= ?Z))
|
127
|
+
end
|
128
|
+
|
129
|
+
def isDigit(c)
|
130
|
+
return (?0 <= c and c <= ?9)
|
131
|
+
end
|
132
|
+
|
133
|
+
def isWhiteSpace(c)
|
134
|
+
return (c == ?\ or c == ?\n or c == ?\t)
|
135
|
+
end
|
136
|
+
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 #herencia simple token
|
12
|
+
attr_reader :lex
|
13
|
+
|
14
|
+
def initialize(type,lex,lineNum,colNum) #lexema que va a leer polimorfismo
|
15
|
+
super(type,lineNum,colNum) #clase padre token
|
16
|
+
|
17
|
+
@lex = lex #instancias de lexical token podran tener @lex
|
18
|
+
end
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: calc_jgomez88
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kent D. Lee - Juan Francisco Cardona Mc-juan camilo gomez
|
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: fcardona@eafit.edu.co-jgomez88@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: []
|