surpass 0.0.7 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +2 -2
- data/Rakefile +14 -16
- data/debug-examples/formula-cell.bin +0 -0
- data/debug-examples/formula-cell.rb +14 -0
- data/debug-examples/formula-record.bin +0 -0
- data/debug-examples/formula-record.rb +15 -0
- data/lib/surpass/ExcelFormula.g +82 -84
- data/lib/surpass/ExcelFormula.tokens +29 -29
- data/lib/surpass/ExcelFormulaLexer.rb +1283 -842
- data/lib/surpass/ExcelFormulaParser.rb +1654 -491
- data/lib/surpass/biff_record.rb +2 -2
- data/lib/surpass/formula.rb +25 -0
- data/lib/surpass/row.rb +1 -1
- data/lib/surpass/utilities.rb +32 -0
- data/lib/surpass/workbook.rb +1 -1
- data/lib/surpass/worksheet.rb +4 -4
- data/lib/surpass.rb +12 -2
- data/surpass.gemspec +8 -9
- metadata +26 -25
- data/lib/surpass/excel_formula.rb +0 -23
- data/out.bin +0 -0
- data/tasks/ann.rake +0 -80
- data/tasks/bones.rake +0 -20
- data/tasks/gem.rake +0 -201
- data/tasks/git.rake +0 -40
- data/tasks/notes.rake +0 -27
- data/tasks/post_load.rake +0 -34
- data/tasks/rdoc.rake +0 -51
- data/tasks/rubyforge.rake +0 -55
- data/tasks/setup.rb +0 -292
- data/tasks/spec.rake +0 -54
- data/tasks/svn.rake +0 -47
- data/tasks/test.rake +0 -40
- data/tasks/zentest.rake +0 -36
data/History.txt
CHANGED
data/Rakefile
CHANGED
@@ -4,27 +4,25 @@
|
|
4
4
|
|
5
5
|
begin
|
6
6
|
require 'bones'
|
7
|
-
Bones.setup
|
8
7
|
rescue LoadError
|
9
|
-
|
10
|
-
load 'tasks/setup.rb'
|
11
|
-
rescue LoadError
|
12
|
-
raise RuntimeError, '### please install the "bones" gem ###'
|
13
|
-
end
|
8
|
+
abort '### Please install the "bones" gem ###'
|
14
9
|
end
|
15
10
|
|
16
11
|
ensure_in_path 'lib'
|
17
12
|
require 'surpass'
|
18
13
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
PROJ.rubyforge.name = 'surpass'
|
14
|
+
Bones {
|
15
|
+
name 'surpass'
|
16
|
+
authors 'Ana Nelson'
|
17
|
+
email 'ana@ananelson.com'
|
18
|
+
url 'http://surpass.rubyforge.org'
|
19
|
+
version Surpass::VERSION
|
20
|
+
}
|
27
21
|
|
28
|
-
|
22
|
+
task :default => 'spec:run'
|
23
|
+
task 'gem:release' => 'test:run'
|
29
24
|
|
30
|
-
|
25
|
+
desc "run antlr compiler"
|
26
|
+
task :antlr do
|
27
|
+
`cd lib/surpass; antlr4ruby ExcelFormula.g`
|
28
|
+
end
|
Binary file
|
Binary file
|
data/lib/surpass/ExcelFormula.g
CHANGED
@@ -7,6 +7,8 @@ options {
|
|
7
7
|
|
8
8
|
@header {
|
9
9
|
RVA_DELTA = {"R" => 0, "V" => 0x20, "A" => 0x40}
|
10
|
+
RVA_DELTA_REF = {"R" => 0, "V" => 0x20, "A" => 0x40, "D" => 0x20}
|
11
|
+
RVA_DELTA_AREA = {"R" => 0, "V" => 0x20, "A" => 0x40, "D" => 0}
|
10
12
|
}
|
11
13
|
|
12
14
|
@init {
|
@@ -28,11 +30,11 @@ expr[arg_type]
|
|
28
30
|
(
|
29
31
|
(
|
30
32
|
EQ { op = [PTGEQ].pack('C') }
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
33
|
+
| NE { op = [PTGNE].pack('C') }
|
34
|
+
| GT { op = [PTGGT].pack('C') }
|
35
|
+
| LT { op = [PTGLT].pack('C') }
|
36
|
+
| GE { op = [PTGGE].pack('C') }
|
37
|
+
| LE { op = [PTGLE].pack('C') }
|
36
38
|
|
37
39
|
)
|
38
40
|
prec0_expr[arg_type] { @rpn += op }
|
@@ -105,7 +107,8 @@ primary[arg_type]
|
|
105
107
|
}
|
106
108
|
| str_tok = STR_CONST
|
107
109
|
{
|
108
|
-
|
110
|
+
s = str_tok.text.gsub("\"", "")
|
111
|
+
@rpn += [PTGSTR].pack("C") + [s.length].pack('v') + s
|
109
112
|
}
|
110
113
|
| int_tok = INT_CONST
|
111
114
|
{
|
@@ -118,22 +121,23 @@ primary[arg_type]
|
|
118
121
|
}
|
119
122
|
| num_tok = NUM_CONST
|
120
123
|
{
|
121
|
-
@rpn += [
|
124
|
+
@rpn += [PTGNUM, num_tok.text.to_f].pack("CE")
|
122
125
|
}
|
123
126
|
| ref2d_tok = REF2D
|
124
127
|
{
|
125
|
-
r, c =
|
128
|
+
r, c = Utilities.cell_to_packed_rowcol(ref2d_tok.text)
|
126
129
|
ptg = PTGREFR + RVA_DELTA[arg_type]
|
127
130
|
@rpn += [ptg, r, c].pack("Cv2")
|
128
131
|
}
|
129
132
|
| ref2d1_tok = REF2D COLON ref2d2_tok = REF2D
|
130
133
|
{
|
131
|
-
r1, c1 =
|
132
|
-
r2, c2 =
|
134
|
+
r1, c1 = Utilities.cell_to_packed_rowcol(ref2d1_tok.text)
|
135
|
+
r2, c2 = Utilities.cell_to_packed_rowcol(ref2d2_tok.text)
|
133
136
|
ptg = PTGAREAR + RVA_DELTA[arg_type]
|
134
|
-
|
137
|
+
@rpn += [ptg, r1, r2, c1, c2].pack("Cv4")
|
135
138
|
}
|
136
|
-
|
139
|
+
|
140
|
+
| sheet1 = sheet
|
137
141
|
{
|
138
142
|
sheet2 = sheet1
|
139
143
|
}
|
@@ -141,13 +145,13 @@ primary[arg_type]
|
|
141
145
|
{
|
142
146
|
ptg = PTGREF3DR + RVA_DELTA[arg_type]
|
143
147
|
rpn_ref2d = ""
|
144
|
-
r1, c1 =
|
148
|
+
r1, c1 = Utilities.cell_to_packed_rowcol(ref3d_ref2d.text)
|
145
149
|
rpn_ref2d = [0x0000, r1, c1].pack("v3")
|
146
150
|
}
|
147
151
|
( COLON ref3d_ref2d2= REF2D
|
148
152
|
{
|
149
153
|
ptg = PTGAREA3DR + RVA_DELTA[arg_type]
|
150
|
-
r2, c2 =
|
154
|
+
r2, c2 = Utilities.cell_to_packed_rowcol(ref3d_ref2d2.text)
|
151
155
|
rpn_ref2d = [0x0000, r1, r2, c1, c2].pack("v5")
|
152
156
|
}
|
153
157
|
)?
|
@@ -156,7 +160,7 @@ primary[arg_type]
|
|
156
160
|
@sheet_references << [sheet1, sheet2, @rpn.size]
|
157
161
|
@rpn += rpn_ref2d
|
158
162
|
}
|
159
|
-
|
163
|
+
| FUNC_IF
|
160
164
|
LP expr["V"] (SEMICOLON | COMMA)
|
161
165
|
{
|
162
166
|
@rpn += [PTGATTR, 0x02, 0].pack("C2v") # tAttrIf
|
@@ -165,44 +169,48 @@ primary[arg_type]
|
|
165
169
|
expr[arg_type] (SEMICOLON | COMMA)
|
166
170
|
{
|
167
171
|
@rpn += [PTGATTR, 0x08, 0].pack("C2v") # tAttrSkip
|
168
|
-
pos1 = @rpn.
|
169
|
-
|
172
|
+
pos1 = @rpn.length - 2
|
173
|
+
|
174
|
+
rem = @rpn.length - (pos0 + 2)
|
175
|
+
@rpn = @rpn[0..pos0] + [pos1-pos0].pack("v") + @rpn[pos0+2, rem] # TODO Check for OBO
|
170
176
|
}
|
171
177
|
expr[arg_type] RP
|
172
178
|
{
|
173
179
|
@rpn += [PTGATTR, 0x08, 3].pack("C2v") # tAttrSkip
|
174
180
|
@rpn += [PTGFUNCVARR, 3, 1].pack("C2v") # 3 = nargs, 1 = IF func
|
175
|
-
pos2 = @rpn.
|
176
|
-
|
181
|
+
pos2 = @rpn.length
|
182
|
+
|
183
|
+
rem = @rpn.length - (pos1 + 2)
|
184
|
+
@rpn = @rpn[0..pos1] + [pos2-(pos1+2)-1].pack("v") + @rpn[pos1+2, rem] # TODO Check for OBO
|
177
185
|
}
|
178
|
-
|
186
|
+
| FUNC_CHOOSE
|
179
187
|
{
|
180
188
|
arg_type = "R"
|
181
189
|
rpn_chunks = []
|
182
190
|
}
|
183
|
-
LP expr["V"]
|
191
|
+
LP expr["V"]
|
184
192
|
{
|
185
|
-
rpn_start = @rpn.
|
186
|
-
ref_markers = [@sheet_references.
|
193
|
+
rpn_start = @rpn.length
|
194
|
+
ref_markers = [@sheet_references.length]
|
187
195
|
}
|
188
196
|
(
|
189
197
|
(SEMICOLON | COMMA)
|
190
|
-
{ mark = @rpn.
|
198
|
+
{ mark = @rpn.length }
|
191
199
|
(
|
192
200
|
expr[arg_type]
|
193
201
|
| { @rpn += [PTGMISSARG].pack("C") }
|
194
202
|
)
|
195
203
|
{
|
196
|
-
|
197
|
-
|
204
|
+
rem = @rpn.length - mark
|
205
|
+
rpn_chunks << @rpn[mark, rem]
|
206
|
+
ref_markers << @sheet_references.size
|
198
207
|
}
|
199
208
|
)*
|
200
209
|
RP
|
201
210
|
{
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
chunklens = rpn_chunks.collect {|c| c.size}
|
211
|
+
@rpn = @rpn[0..rpn_start]
|
212
|
+
nc = rpn_chunks.length
|
213
|
+
chunklens = rpn_chunks.collect {|c| c.length}
|
206
214
|
skiplens = [0] * nc
|
207
215
|
skiplens[-1] = 3
|
208
216
|
|
@@ -219,80 +227,73 @@ primary[arg_type]
|
|
219
227
|
(0...nc).each do |i|
|
220
228
|
(ref_markers[i]...ref_markers[i+1]).each do |r|
|
221
229
|
ref = @sheet_references[r]
|
222
|
-
@sheet_references[r] = [
|
230
|
+
@sheet_references[r] = [ref[0], ref[1], ref[2] + chunk_shift]
|
223
231
|
end
|
224
232
|
chunk_shift += 4 # size of tAttrSkip
|
225
233
|
end
|
226
234
|
|
227
235
|
choose_rpn = []
|
228
|
-
choose_rpn
|
229
|
-
choose_rpn
|
236
|
+
choose_rpn << [PTGATTR, 0x04, nc].pack("CCv") # 0x04 is tAttrChoose
|
237
|
+
choose_rpn << jump_pos.pack("v*")
|
230
238
|
|
231
239
|
(0...nc).each do |i|
|
232
240
|
choose_rpn << rpn_chunks[i]
|
233
241
|
choose_rpn << [PTGATTR, 0x08, skiplens[i]].pack("CCv") # 0x08 is tAttrSkip
|
234
242
|
end
|
235
|
-
choose_rpn
|
243
|
+
choose_rpn << [PTGFUNCVARV, nc+1, 100].pack("CCv") # 100 is CHOOSE fn
|
236
244
|
@rpn += choose_rpn.join
|
237
245
|
}
|
238
|
-
|
239
246
|
| name_tok = NAME
|
240
247
|
{
|
241
|
-
|
242
|
-
# TODO: handle references to defined names here
|
248
|
+
raise "[formula] found unexpected NAME token #{name_tok.text}"
|
243
249
|
}
|
244
250
|
| func_tok = NAME
|
245
251
|
{
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
# # The name of the add-in function is passed as the 1st arg
|
260
|
-
# # of the hidden XCALL function
|
261
|
-
# self.xcall_references.append((func_toku, len(self.rpn) + 1))
|
262
|
-
# self.rpn += struct.pack("<BHHH",
|
263
|
-
# ptgNameXR,
|
264
|
-
# 0xadde, # ##PATCHME## index to REF entry in EXTERNSHEET record
|
265
|
-
# 0xefbe, # ##PATCHME## one-based index to EXTERNNAME record
|
266
|
-
# 0x0000) # unused
|
252
|
+
func_toku = func_tok.text.upcase
|
253
|
+
if STD_FUNC_BY_NAME.has_key?(func_toku)
|
254
|
+
opcode, min_argc, max_argc, func_type, arg_type_str = STD_FUNC_BY_NAME[func_toku]
|
255
|
+
arg_type_list = arg_type_str.split
|
256
|
+
else
|
257
|
+
raise "[formula] unknown function #{func_tok.text}"
|
258
|
+
end
|
259
|
+
xcall = (opcode < 0)
|
260
|
+
|
261
|
+
if xcall
|
262
|
+
@xcall_references << [func_toku, @rpn.size + 1]
|
263
|
+
@rpn += [PTGNAMEXR, 0xadde, 0xefbe, 0x0000].pack("Cvvv")
|
264
|
+
end
|
267
265
|
}
|
268
266
|
LP arg_count = expr_list[arg_type_list, min_argc, max_argc] RP
|
269
267
|
{
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
268
|
+
if (arg_count > max_argc) || (arg_count < min_argc)
|
269
|
+
raise "#{arg_count} parameters for function: #{func_tok.text}"
|
270
|
+
end
|
271
|
+
|
272
|
+
if xcall
|
273
|
+
func_ptg = PTGFUNCVARR + RVA_DELTA[func_type]
|
274
|
+
@rpn += [func_ptg, arg_count + 1, 255].pack("CCv") # 255 is magic XCALL function
|
275
|
+
elsif (min_argc == max_argc)
|
276
|
+
func_ptg = PTGFUNCR + RVA_DELTA[func_type]
|
277
|
+
@rpn += [func_ptg, opcode].pack("Cv")
|
278
|
+
elsif (arg_count == 1) && (func_tok.text.upcase == "SUM")
|
279
|
+
@rpn += [PTGATTR, 0x10, 0].pack("CCv") # tAttrSum
|
280
|
+
else
|
281
|
+
func_ptg = PTGFUNCVARR + RVA_DELTA[func_type]
|
282
|
+
@rpn += [func_ptg, arg_count, opcode].pack("CCv")
|
283
|
+
end
|
284
284
|
}
|
285
285
|
| LP expr[arg_type] RP
|
286
286
|
{
|
287
287
|
@rpn += [PTGPAREN].pack('C')
|
288
288
|
}
|
289
289
|
;
|
290
|
+
|
290
291
|
|
291
292
|
expr_list[arg_type_list, min_argc, max_argc] returns [arg_cnt]
|
292
293
|
@members{
|
293
|
-
|
294
|
-
|
295
|
-
|
294
|
+
arg_cnt = 0
|
295
|
+
arg_type = arg_type_list[arg_cnt]
|
296
|
+
}
|
296
297
|
: expr[arg_type] { arg_cnt += 1 }
|
297
298
|
(
|
298
299
|
{
|
@@ -321,14 +322,10 @@ sheet returns[ref]
|
|
321
322
|
| sheet_ref_int = INT_CONST
|
322
323
|
{ ref = sheet_ref_int.text }
|
323
324
|
| sheet_ref_quote = QUOTENAME
|
324
|
-
{ ref = sheet_ref_quote.text[1
|
325
|
+
{ ref = sheet_ref_quote.text[1, len(sheet_ref_quote.text) - 1].replace("''", "'") }
|
325
326
|
;
|
326
327
|
|
327
|
-
|
328
|
-
|
329
|
-
;
|
330
|
-
|
331
|
-
fragment
|
328
|
+
|
332
329
|
EQ: '=';
|
333
330
|
LT: '<';
|
334
331
|
GT: '>';
|
@@ -352,11 +349,11 @@ PERCENT: '%';
|
|
352
349
|
POWER: '^';
|
353
350
|
BANG: '!';
|
354
351
|
|
355
|
-
DIGIT: '0'..'9';
|
352
|
+
fragment DIGIT: '0'..'9';
|
356
353
|
|
357
354
|
INT_CONST: DIGIT+ ;
|
358
|
-
NUM_CONST: DIGIT* '.' DIGIT+ (('E'|'e') ('+'|'-')? DIGIT+)?;
|
359
|
-
STR_CONST: '"' ~'"' '"';
|
355
|
+
NUM_CONST: DIGIT* '.' DIGIT+ (('E'|'e') ('+'|'-')? DIGIT+)?;
|
356
|
+
STR_CONST: '"' (~'"')+ '"';
|
360
357
|
REF2D: '$'? ('A'..'I')? ('A'..'Z') '$'? DIGIT+;
|
361
358
|
TRUE_CONST: ('T'|'t') ('R'|'r') ('U'|'u') ('E'|'e') ;
|
362
359
|
FALSE_CONST: ('F'|'f') ('A'|'a') ('L'|'l') ('S'|'s') ('E'|'e') ;
|
@@ -364,3 +361,4 @@ NAME: '\w[\.\w]*' ;
|
|
364
361
|
QUOTENAME: '\'(?:[^\']|\'\')*\'';
|
365
362
|
FUNC_IF: 'IF';
|
366
363
|
FUNC_CHOOSE: 'CHOOSE';
|
364
|
+
|
@@ -1,30 +1,30 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
QUOTENAME=31
|
9
|
-
LT=19
|
10
|
-
NE=21
|
11
|
-
GT=20
|
12
|
-
FUNC_IF=32
|
13
|
-
RP=27
|
14
|
-
FALSE_CONST=13
|
1
|
+
GE=8
|
2
|
+
LT=7
|
3
|
+
NUM_CONST=21
|
4
|
+
PERCENT=16
|
5
|
+
REF2D=22
|
6
|
+
CONCAT=10
|
7
|
+
RP=29
|
15
8
|
LP=26
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
COLON=
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
9
|
+
INT_CONST=20
|
10
|
+
STR_CONST=19
|
11
|
+
POWER=15
|
12
|
+
SUB=12
|
13
|
+
FUNC_CHOOSE=30
|
14
|
+
SEMICOLON=27
|
15
|
+
BANG=24
|
16
|
+
TRUE_CONST=17
|
17
|
+
MUL=13
|
18
|
+
COLON=23
|
19
|
+
NAME=31
|
20
|
+
FALSE_CONST=18
|
21
|
+
COMMA=28
|
22
|
+
GT=6
|
23
|
+
DIGIT=33
|
24
|
+
EQ=4
|
25
|
+
DIV=14
|
26
|
+
FUNC_IF=25
|
27
|
+
QUOTENAME=32
|
28
|
+
LE=9
|
29
|
+
NE=5
|
30
|
+
ADD=11
|