fexpr 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.
- data/LICENSE +1 -0
- data/README.md +1 -0
- data/lib/fexpr.rb +8 -0
- data/lib/fexpr/base.rb +247 -0
- data/lib/fexpr/main.rb +42 -0
- metadata +68 -0
data/LICENSE
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Apache
|
data/README.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Floting point version of expr
|
data/lib/fexpr.rb
ADDED
data/lib/fexpr/base.rb
ADDED
@@ -0,0 +1,247 @@
|
|
1
|
+
module FExpr
|
2
|
+
|
3
|
+
class Evaluator
|
4
|
+
|
5
|
+
def initialize(argv)
|
6
|
+
@argv = argv
|
7
|
+
@node_stack = []
|
8
|
+
@opt_trace = false
|
9
|
+
end
|
10
|
+
|
11
|
+
# Void -> String
|
12
|
+
def eval
|
13
|
+
@toks = Array.new @argv
|
14
|
+
@tok = nil
|
15
|
+
next_token
|
16
|
+
expr
|
17
|
+
evaluate.to_s
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
# Classes
|
23
|
+
|
24
|
+
class Node
|
25
|
+
def to_s
|
26
|
+
to_string 0
|
27
|
+
end
|
28
|
+
def to_string(depth)
|
29
|
+
raise 'Implement to_string, stupid!'
|
30
|
+
end
|
31
|
+
def eval
|
32
|
+
raise 'Implement eval, stupid!'
|
33
|
+
end
|
34
|
+
def x(n)
|
35
|
+
Array.new(n) { |x| '.' }.join(' ') + ' '
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class OpNode < Node
|
40
|
+
attr_reader :op , :a, :b
|
41
|
+
def initialize(op,a,b)
|
42
|
+
@op = op
|
43
|
+
@a = a
|
44
|
+
@b = b
|
45
|
+
end
|
46
|
+
def eval
|
47
|
+
a = @a.eval
|
48
|
+
b = @b.eval
|
49
|
+
case @op
|
50
|
+
when '|' then a and a != 0 ? a : b
|
51
|
+
when '&' then (a and a!=0 and b and b!=0) ? a : 0
|
52
|
+
when '=' then a == b
|
53
|
+
when '>' then a > b
|
54
|
+
when '>=' then a >= b
|
55
|
+
when '<' then a < b
|
56
|
+
when '<=' then a <= b
|
57
|
+
when '!=' then a != b
|
58
|
+
when '+' then a + b
|
59
|
+
when '-' then a - b
|
60
|
+
when '*' then a * b
|
61
|
+
when 'x' then a * b
|
62
|
+
when '/' then a / b
|
63
|
+
when '%' then a.to_i % b.to_i
|
64
|
+
else error 'Invalid operator \'' + @op + '\''
|
65
|
+
end
|
66
|
+
end
|
67
|
+
def to_string(n)
|
68
|
+
str = x(n) + @op + "\n"
|
69
|
+
str += a.to_string(n+1) + "\n"
|
70
|
+
str += b.to_string(n+1)
|
71
|
+
return str
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class NumNode < Node
|
76
|
+
attr_reader :val
|
77
|
+
def initialize(val)
|
78
|
+
@val = val
|
79
|
+
end
|
80
|
+
def eval
|
81
|
+
@val
|
82
|
+
end
|
83
|
+
def to_string(n)
|
84
|
+
x(n) + @val.to_s
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Misc
|
89
|
+
|
90
|
+
def trace(s)
|
91
|
+
STDERR.puts s if @opt_trace
|
92
|
+
end
|
93
|
+
|
94
|
+
def shift(t)
|
95
|
+
shift_one_of [t]
|
96
|
+
end
|
97
|
+
|
98
|
+
def shift_one_of(ts)
|
99
|
+
found = false
|
100
|
+
ts.each do |t|
|
101
|
+
if @tok == t
|
102
|
+
next_token
|
103
|
+
return t
|
104
|
+
end
|
105
|
+
end
|
106
|
+
return nil
|
107
|
+
end
|
108
|
+
|
109
|
+
def next_token
|
110
|
+
if not @toks.empty?
|
111
|
+
@tok = @toks.shift.gsub /[,_\$]/,''
|
112
|
+
end
|
113
|
+
@tok
|
114
|
+
end
|
115
|
+
|
116
|
+
def error(msg)
|
117
|
+
STDERR.puts msg
|
118
|
+
STDERR.flush
|
119
|
+
exit 1
|
120
|
+
end
|
121
|
+
|
122
|
+
def push(n)
|
123
|
+
@node_stack << NumNode.new(n)
|
124
|
+
end
|
125
|
+
|
126
|
+
def push_binop(op)
|
127
|
+
b = pop
|
128
|
+
a = pop
|
129
|
+
@node_stack << OpNode.new(op,a,b)
|
130
|
+
end
|
131
|
+
|
132
|
+
def pop
|
133
|
+
@node_stack.pop
|
134
|
+
end
|
135
|
+
|
136
|
+
# Void -> String
|
137
|
+
def evaluate
|
138
|
+
trace @node_stack
|
139
|
+
pop.eval
|
140
|
+
end
|
141
|
+
|
142
|
+
# Parsing
|
143
|
+
|
144
|
+
# -------------------------------------------------------------------------------------------
|
145
|
+
# Grammar:
|
146
|
+
#
|
147
|
+
# expr ::= or_expr
|
148
|
+
# or_expr ::= or_expr '|' and_expr
|
149
|
+
# and_expr ::= and_expr '&' rel_expr
|
150
|
+
# rel_expr ::= rel_expr ( '=' | '>' | '>=' | '<' | '<=' | '!=' )add_expr
|
151
|
+
# add_expr ::= add_expr ( '+' | '_' ) mul_expr
|
152
|
+
# mul_expr ::= mul_expr ( 'x' | '*' | '/' | '%' ) sim_expr
|
153
|
+
# sim_expr ::= <number>
|
154
|
+
#
|
155
|
+
# The Re-factored Grammar:
|
156
|
+
# -----------
|
157
|
+
#
|
158
|
+
# expr ::= or_expr
|
159
|
+
# or_expr ::= and_expr or_expr_tail
|
160
|
+
# or_expr_tail ::= '|' and_expr or_expr_tail
|
161
|
+
# and_expr ::= rel_expr and_expr_tail
|
162
|
+
# and_expr_tail ::= '&' rel_expr and_expr_tail
|
163
|
+
# rel_expr ::= add_expr rel_expr_tail
|
164
|
+
# rel_expr_tail ::= ( '=' | '>' | '>=' | '<' | '<=' | '!=' ) add_expr rel_expr_tail
|
165
|
+
# add_expr ::= mul_expr and_expr_tail
|
166
|
+
# add_expr_tail ::= ( '+' | '-' ) mul_expr add_expr_tail
|
167
|
+
# mul_expr ::= sim_expr mul_expr_tail
|
168
|
+
# mul_expr_tail ::= ( 'x' | '*' | '/' | '%' ) sim_expr mul_expr_tail
|
169
|
+
# sim_expr ::= <number>
|
170
|
+
# -------------------------------------------------------------------------------------------
|
171
|
+
|
172
|
+
def expr
|
173
|
+
or_expr
|
174
|
+
end
|
175
|
+
|
176
|
+
def or_expr
|
177
|
+
and_expr
|
178
|
+
or_expr_tail
|
179
|
+
end
|
180
|
+
|
181
|
+
def or_expr_tail
|
182
|
+
op = shift '|'
|
183
|
+
return if not op
|
184
|
+
and_expr
|
185
|
+
or_expr_tail
|
186
|
+
push_binop op
|
187
|
+
end
|
188
|
+
|
189
|
+
def and_expr
|
190
|
+
rel_expr
|
191
|
+
and_expr_tail
|
192
|
+
end
|
193
|
+
|
194
|
+
def and_expr_tail
|
195
|
+
op = shift '&'
|
196
|
+
return if not op
|
197
|
+
rel_expr
|
198
|
+
and_expr_tail
|
199
|
+
push_binop op
|
200
|
+
end
|
201
|
+
|
202
|
+
def rel_expr
|
203
|
+
add_expr
|
204
|
+
rel_expr_tail
|
205
|
+
end
|
206
|
+
|
207
|
+
def rel_expr_tail
|
208
|
+
op = shift_one_of ['=','>','>=','<','<=','!=']
|
209
|
+
return if not op
|
210
|
+
add_expr
|
211
|
+
rel_expr_tail
|
212
|
+
push_binop op
|
213
|
+
end
|
214
|
+
|
215
|
+
def add_expr
|
216
|
+
mul_expr
|
217
|
+
add_expr_tail
|
218
|
+
end
|
219
|
+
|
220
|
+
def add_expr_tail
|
221
|
+
op = shift_one_of ['+','-']
|
222
|
+
return if not op
|
223
|
+
mul_expr
|
224
|
+
add_expr_tail
|
225
|
+
push_binop op
|
226
|
+
end
|
227
|
+
|
228
|
+
def mul_expr
|
229
|
+
sim_expr
|
230
|
+
mul_expr_tail
|
231
|
+
end
|
232
|
+
|
233
|
+
def mul_expr_tail
|
234
|
+
op = shift_one_of ['x','*','/','%']
|
235
|
+
return if not op
|
236
|
+
sim_expr
|
237
|
+
mul_expr_tail
|
238
|
+
push_binop op
|
239
|
+
end
|
240
|
+
|
241
|
+
def sim_expr
|
242
|
+
n = @tok.to_f
|
243
|
+
push n
|
244
|
+
next_token
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
data/lib/fexpr/main.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
module FExpr
|
2
|
+
|
3
|
+
class Main
|
4
|
+
|
5
|
+
def main(argv)
|
6
|
+
puts real_main argv
|
7
|
+
end
|
8
|
+
|
9
|
+
# Void -> Float
|
10
|
+
def real_main(argv)
|
11
|
+
|
12
|
+
# maybe help
|
13
|
+
print_help and return 0 if argv.empty?
|
14
|
+
|
15
|
+
# maybe testing
|
16
|
+
run_test and return if argv[0] == '-test'
|
17
|
+
if argv[0][0..0] == '-'
|
18
|
+
@opt_trace = true
|
19
|
+
argv.shift
|
20
|
+
end
|
21
|
+
|
22
|
+
# cleanse the arguments
|
23
|
+
args = argv.map {|arg| arg.gsub /,/,''}
|
24
|
+
|
25
|
+
# run
|
26
|
+
evaluator = Evaluator.new args
|
27
|
+
evaluator.eval
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def print_help
|
33
|
+
puts '***************************************************'
|
34
|
+
puts 'Replace integer (or int) with floating point number'
|
35
|
+
puts 'And forget about the \':\' operator'
|
36
|
+
puts '***************************************************'
|
37
|
+
sleep 2
|
38
|
+
system 'man', 'expr'
|
39
|
+
true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fexpr
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 9
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: "0.1"
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Jeffrey Palm
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2013-04-02 00:00:00 Z
|
18
|
+
dependencies: []
|
19
|
+
|
20
|
+
description: Floating point fexpr
|
21
|
+
email: jeff@jeffpalm.com
|
22
|
+
executables: []
|
23
|
+
|
24
|
+
extensions: []
|
25
|
+
|
26
|
+
extra_rdoc_files: []
|
27
|
+
|
28
|
+
files:
|
29
|
+
- README.md
|
30
|
+
- LICENSE
|
31
|
+
- lib/fexpr.rb
|
32
|
+
- lib/fexpr/base.rb
|
33
|
+
- lib/fexpr/main.rb
|
34
|
+
homepage: http://github.com/spudtrooper/fexpr
|
35
|
+
licenses: []
|
36
|
+
|
37
|
+
post_install_message:
|
38
|
+
rdoc_options:
|
39
|
+
- --charset=UTF-8
|
40
|
+
require_paths:
|
41
|
+
- lib
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
43
|
+
none: false
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
hash: 3
|
48
|
+
segments:
|
49
|
+
- 0
|
50
|
+
version: "0"
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
hash: 3
|
57
|
+
segments:
|
58
|
+
- 0
|
59
|
+
version: "0"
|
60
|
+
requirements: []
|
61
|
+
|
62
|
+
rubyforge_project: fexpr
|
63
|
+
rubygems_version: 1.8.24
|
64
|
+
signing_key:
|
65
|
+
specification_version: 2
|
66
|
+
summary: Fexpr
|
67
|
+
test_files: []
|
68
|
+
|