calc_Scarvaj9 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 +7 -0
- data/bin/calc +22 -0
- data/lib/ast.rb +82 -0
- data/lib/calcex.rb +3 -0
- data/lib/calculator.rb +16 -0
- data/lib/parser.rb +121 -0
- data/lib/scanner.rb +127 -0
- data/lib/token.rb +20 -0
- metadata +51 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9e6376f35b61ffc6fba759d3af3cb930cd4ceba0
|
4
|
+
data.tar.gz: 15723f82c01b7dbc1f788dc66c588635b0fbfa2e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3c7cfc286213df0f4bab3987044923363151a733741770063092e3f1b23d48d617a981779616f4a8eb648fc7a38b31d2672e9f4b47f981fb8c4bdc150471d3de
|
7
|
+
data.tar.gz: b20579f836f0bf1be7b0e0dcf7dad3839729158a981913e4f18f77c33c238ce50cbd2a247f9a431e36f3277324d6234829d1a9c65eb5c7a1469034c9992424eb
|
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,82 @@
|
|
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 TimeNode < 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 DivideNode < 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 StoreNode < UnaryNode
|
51
|
+
def initialize (subTree)
|
52
|
+
super(subTree)
|
53
|
+
end
|
54
|
+
def evaluate
|
55
|
+
$calc.memory = subTree.evaluate
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class RecallNode
|
60
|
+
def evaluate
|
61
|
+
$calc.memory
|
62
|
+
end
|
63
|
+
end
|
64
|
+
class SubNode < BinaryNode
|
65
|
+
def initialize(left, right)
|
66
|
+
super(left,right)
|
67
|
+
end
|
68
|
+
|
69
|
+
def evaluate
|
70
|
+
left.evaluate - right.evaluate
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class NumNode
|
75
|
+
def initialize(num)
|
76
|
+
@num = num
|
77
|
+
end
|
78
|
+
|
79
|
+
def evaluate
|
80
|
+
@num
|
81
|
+
end
|
82
|
+
end
|
data/lib/calcex.rb
ADDED
data/lib/calculator.rb
ADDED
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
|
+
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
|
+
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
|
+
|
54
|
+
t = @scan.getToken
|
55
|
+
|
56
|
+
if t.type == :times then
|
57
|
+
return ResTerm(TimesNode.new(e,Storable()))
|
58
|
+
end
|
59
|
+
|
60
|
+
if t.type == :divide then
|
61
|
+
return ResTerm(DivideNode.new(e,Storable()))
|
62
|
+
end
|
63
|
+
@scan.putBackToken
|
64
|
+
e
|
65
|
+
end
|
66
|
+
|
67
|
+
def Storable()
|
68
|
+
|
69
|
+
result = Factor()
|
70
|
+
|
71
|
+
t = @scan.getToken
|
72
|
+
|
73
|
+
if t.type == :keyword then
|
74
|
+
if t.lex == "S" then
|
75
|
+
|
76
|
+
return StoreNode.new(result)
|
77
|
+
end
|
78
|
+
print "Expected S found #{t.lex}"
|
79
|
+
puts "at line: #{t.line} col: #{t.col} "
|
80
|
+
raise ParserError.new
|
81
|
+
|
82
|
+
end
|
83
|
+
@scan.putBackToken
|
84
|
+
|
85
|
+
result
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
def Factor()
|
90
|
+
t = @scan.getToken
|
91
|
+
|
92
|
+
if t.type == :number then
|
93
|
+
return NumNode.new(t.lex.to_i)
|
94
|
+
end
|
95
|
+
|
96
|
+
if t.type == :keyword then
|
97
|
+
if t.lex == "R" then
|
98
|
+
return RecallNode.new
|
99
|
+
end
|
100
|
+
|
101
|
+
puts "Error"
|
102
|
+
raise ParseError.new
|
103
|
+
end
|
104
|
+
|
105
|
+
if t.type == :lparen then
|
106
|
+
result = Expr()
|
107
|
+
t = @scan.getToken
|
108
|
+
if t.type == :rparen then
|
109
|
+
return result
|
110
|
+
end
|
111
|
+
print "we found an error on Factor::rparen"
|
112
|
+
puts "at line: #{t.line} col: #{t.col} "
|
113
|
+
raise ParserError.new
|
114
|
+
|
115
|
+
end
|
116
|
+
print "we found an error on Factor::lparen"
|
117
|
+
puts "at line: #{t.line} col: #{t.col} "
|
118
|
+
raise ParserError.new
|
119
|
+
|
120
|
+
end
|
121
|
+
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,20 @@
|
|
1
|
+
|
2
|
+
class Token
|
3
|
+
attr_reader :type, :line, :col
|
4
|
+
|
5
|
+
def initialize(type,lineNum,colNum)
|
6
|
+
@type = type
|
7
|
+
@line = lineNum
|
8
|
+
@col = colNum
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class LexicalToken < Token
|
13
|
+
attr_reader :lex
|
14
|
+
|
15
|
+
def initialize(type,lex,lineNum,colNum)
|
16
|
+
super(type,lineNum,colNum)
|
17
|
+
|
18
|
+
@lex = lex
|
19
|
+
end
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: calc_Scarvaj9
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kent D. Lee - Juan Francisco Cardona Mc - Smith Alexis Carvajl O
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-10-10 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: An calculator implementation on ruby
|
14
|
+
email: scarvaj9@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: []
|