twowaysql 0.2.0

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.
Files changed (39) hide show
  1. data/History.txt +3 -0
  2. data/License.txt +13 -0
  3. data/Manifest.txt +38 -0
  4. data/README.txt +382 -0
  5. data/Rakefile +4 -0
  6. data/config/hoe.rb +73 -0
  7. data/config/requirements.rb +15 -0
  8. data/issues/issue-25efcfc383f3b0f6c0e2730ae7c2975bb2b3de26.yaml +18 -0
  9. data/issues/issue-39023ea09e17e2d64bcef03aa59cdfe38b78ad5b.yaml +26 -0
  10. data/issues/issue-4bc308d55ae91f266e656162a4147d356de1166c.yaml +24 -0
  11. data/issues/issue-897995fa10377eabdf597e8e7692f17087c76923.yaml +26 -0
  12. data/issues/issue-bd38c1cdc965d73dd629a81db2de1bcdcf4b10b8.yaml +26 -0
  13. data/issues/issue-f2b773020b54f839c03d899b38b5113c8fd991df.yaml +18 -0
  14. data/issues/issue-f39b907d01d7fa93df8c7a9de2e1b5e27727ee0a.yaml +18 -0
  15. data/issues/issue-f64d73ed4f9854f1ded77e6496dbf59cfb3770a7.yaml +18 -0
  16. data/issues/project.yaml +16 -0
  17. data/lib/twowaysql/node.rb +239 -0
  18. data/lib/twowaysql/parser.rb +489 -0
  19. data/lib/twowaysql/parser.y +226 -0
  20. data/lib/twowaysql/template.rb +75 -0
  21. data/lib/twowaysql/version.rb +9 -0
  22. data/lib/twowaysql.rb +6 -0
  23. data/script/console +10 -0
  24. data/script/destroy +14 -0
  25. data/script/generate +14 -0
  26. data/script/txt2html +82 -0
  27. data/setup.rb +1585 -0
  28. data/spec/large_sql_spec.rb +142 -0
  29. data/spec/learning_regex_spec.rb +234 -0
  30. data/spec/spec.opts +0 -0
  31. data/spec/spec_helper.rb +10 -0
  32. data/spec/twowaysql_spec.rb +736 -0
  33. data/tasks/deployment.rake +53 -0
  34. data/tasks/ditz.rake +8 -0
  35. data/tasks/environment.rake +7 -0
  36. data/tasks/racc.rake +23 -0
  37. data/tasks/rspec.rake +21 -0
  38. data/tasks/website.rake +17 -0
  39. metadata +104 -0
@@ -0,0 +1,489 @@
1
+ #
2
+ # DO NOT MODIFY!!!!
3
+ # This file is automatically generated by racc 1.4.5
4
+ # from racc grammer file "lib/twowaysql/parser.y".
5
+ #
6
+
7
+ require 'racc/parser'
8
+
9
+
10
+ module TwoWaySQL
11
+
12
+ class Parser < Racc::Parser
13
+
14
+ module_eval <<'..end lib/twowaysql/parser.y modeval..id42b80b1728', 'lib/twowaysql/parser.y', 128
15
+
16
+ require 'strscan'
17
+
18
+ def initialize(opts={})
19
+ opts = {
20
+ :debug => true,
21
+ :preserve_space => true,
22
+ :preserve_comment => true,
23
+ :preserve_eol => true
24
+ }.merge(opts)
25
+ @yydebug = opts[:debug]
26
+ @preserve_space = opts[:preserve_space]
27
+ @preserve_comment = opts[:preserve_comment]
28
+ @preserve_eol = opts[:preserve_eol]
29
+ @num_questions = 0
30
+ end
31
+
32
+ BEGIN_SUBSTITUTION = '(\/|\#)\*([^\*]+)\*\1'
33
+ PAREN_EXAMPLE = '\([^\)]+\)'
34
+ SUBSTITUTION_PATTERN = /\A#{BEGIN_SUBSTITUTION}\s*/
35
+ PAREN_SUBSTITUTION_PATTERN = /\A#{BEGIN_SUBSTITUTION}\s*#{PAREN_EXAMPLE}/
36
+
37
+ CONDITIONAL_PATTERN = /\A(\/|\#)\*(IF)\s+([^\*]+)\s*\*\1/
38
+ BEGIN_END_PATTERN = /\A(\/|\#)\*(BEGIN|END)\s*\*\1/
39
+ QUOTED_STRING_PATTERN = /\A(\'(?:[^\']+|\'\')*\')/ ## quoted string
40
+ SPLIT_TOKEN_PATTERN = /\A(\S+?)(?=\s*(?:(?:\/|\#)\*|-{2,}|\(|\)|\,))/ ## stop on delimiters --,/*,#*,',',(,)
41
+ ELSE_PATTERN = /\A\-{2,}\s*ELSE\s*/
42
+ AND_PATTERN = /\A(\s*AND\s+)/
43
+ OR_PATTERN = /\A(\s*OR\s+)/
44
+ LITERAL_PATTERN = /\A([^;\s]+)/
45
+ SPACES_PATTERN = /\A(\s+)/
46
+ QUESTION_PATTERN = /\A\?/
47
+ COMMA_PATTERN = /\A\,/
48
+ LPAREN_PATTERN = /\A\(/
49
+ RPAREN_PATTERN = /\A\)/
50
+ ACTUAL_COMMENT_PATTERN = /\A(\/|\#)\*\s+(.+)\s*\*\1/ ## start with spaces
51
+ SEMICOLON_AT_INPUT_END_PATTERN = /\A\;\s*\Z/
52
+ UNMATCHED_COMMENT_START_PATTERN = /\A(?:(?:\/|\#)\*)/
53
+
54
+
55
+ def parse( io )
56
+ @q = []
57
+ io.each do |line|
58
+ s = StringScanner.new(line.rstrip)
59
+ until s.eos? do
60
+ case
61
+ when s.scan(AND_PATTERN)
62
+ @q.push [ :AND, s[1] ]
63
+ when s.scan(OR_PATTERN)
64
+ @q.push [ :OR, s[1] ]
65
+ when s.scan(SPACES_PATTERN)
66
+ @q.push [ :SPACES, s[1] ] if @preserve_space
67
+ when s.scan(QUESTION_PATTERN)
68
+ @q.push [ :QUESTION, nil ]
69
+ when s.scan(COMMA_PATTERN)
70
+ @q.push [ :COMMA, ',' ]
71
+ when s.scan(LPAREN_PATTERN)
72
+ @q.push [ :LPAREN, '(' ]
73
+ when s.scan(RPAREN_PATTERN)
74
+ @q.push [ :RPAREN, ')' ]
75
+ when s.scan(ELSE_PATTERN)
76
+ @q.push [ :ELSE, nil ]
77
+ when s.scan(ACTUAL_COMMENT_PATTERN)
78
+ @q.push [ :ACTUAL_COMMENT, s[2] ] if @preserve_comment
79
+ when s.scan(BEGIN_END_PATTERN)
80
+ @q.push [ s[2].intern, nil ]
81
+ when s.scan(CONDITIONAL_PATTERN)
82
+ @q.push [ s[2].intern, s[3] ]
83
+ when s.scan(PAREN_SUBSTITUTION_PATTERN)
84
+ @q.push [ :PAREN_SUBSTITUTION, s[2] ]
85
+ when s.scan(SUBSTITUTION_PATTERN)
86
+ @q.push [ :SUBSTITUTION, s[2] ]
87
+ when s.scan(QUOTED_STRING_PATTERN)
88
+ @q.push [ :QUOTED, s[1] ]
89
+ when s.scan(SPLIT_TOKEN_PATTERN)
90
+ @q.push [ :CHARS, s[1] ]
91
+ when s.scan(UNMATCHED_COMMENT_START_PATTERN) ## unmatched comment start, '/*','#*'
92
+ raise Racc::ParseError, "## unmatched comment. cannot parse [#{s.rest}]"
93
+ when s.scan(LITERAL_PATTERN) ## other string token
94
+ @q.push [ :CHARS, s[1] ]
95
+ when s.scan(SEMICOLON_AT_INPUT_END_PATTERN)
96
+ #drop semicolon at input end
97
+ else
98
+ raise Racc::ParseError, "## cannot parse [#{s.rest}]"
99
+ end
100
+ end
101
+
102
+ @q.push [ :EOL, nil ] if @preserve_eol
103
+ end
104
+
105
+ @q.push [ false, nil ]
106
+
107
+ ## cal racc's private parse method
108
+ do_parse
109
+ end
110
+
111
+ def next_token
112
+ @q.shift
113
+ end
114
+ ..end lib/twowaysql/parser.y modeval..id42b80b1728
115
+
116
+ ##### racc 1.4.5 generates ###
117
+
118
+ racc_reduce_table = [
119
+ 0, 0, :racc_error,
120
+ 1, 20, :_reduce_1,
121
+ 0, 21, :_reduce_2,
122
+ 2, 21, :_reduce_3,
123
+ 1, 22, :_reduce_none,
124
+ 1, 22, :_reduce_none,
125
+ 1, 22, :_reduce_none,
126
+ 3, 25, :_reduce_7,
127
+ 4, 24, :_reduce_8,
128
+ 2, 27, :_reduce_9,
129
+ 0, 27, :_reduce_10,
130
+ 1, 26, :_reduce_none,
131
+ 1, 26, :_reduce_none,
132
+ 1, 26, :_reduce_none,
133
+ 2, 28, :_reduce_14,
134
+ 2, 29, :_reduce_15,
135
+ 1, 23, :_reduce_16,
136
+ 1, 23, :_reduce_17,
137
+ 1, 23, :_reduce_18,
138
+ 1, 23, :_reduce_19,
139
+ 1, 23, :_reduce_20,
140
+ 1, 23, :_reduce_21,
141
+ 1, 23, :_reduce_22,
142
+ 1, 23, :_reduce_23,
143
+ 1, 23, :_reduce_24,
144
+ 1, 23, :_reduce_25,
145
+ 1, 23, :_reduce_26,
146
+ 1, 23, :_reduce_none,
147
+ 2, 30, :_reduce_28,
148
+ 3, 30, :_reduce_29,
149
+ 2, 30, :_reduce_30,
150
+ 3, 30, :_reduce_31,
151
+ 1, 30, :_reduce_32 ]
152
+
153
+ racc_reduce_n = 33
154
+
155
+ racc_shift_n = 44
156
+
157
+ racc_action_table = [
158
+ 9, 36, 14, 43, 17, 19, 21, 22, 23, 4,
159
+ 6, 8, 11, 13, 15, 16, 18, 9, 24, 14,
160
+ 3, 17, 19, 21, 22, 23, 4, 6, 8, 11,
161
+ 13, 15, 16, 18, 9, nil, 14, nil, 17, 19,
162
+ 21, 22, 23, 4, 6, 8, 11, 13, 15, 16,
163
+ 18, 9, nil, 14, nil, 17, 19, 21, 22, 23,
164
+ 4, 6, 8, 11, 13, 15, 16, 18, 9, 35,
165
+ 14, nil, 17, 19, 21, 22, 23, 4, 6, 8,
166
+ 11, 13, 15, 16, 18, 32, 33, 34, 27, 29,
167
+ 27, 29, 40, 41 ]
168
+
169
+ racc_action_check = [
170
+ 39, 26, 39, 37, 39, 39, 39, 39, 39, 39,
171
+ 39, 39, 39, 39, 39, 39, 39, 2, 3, 2,
172
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
173
+ 2, 2, 2, 2, 38, nil, 38, nil, 38, 38,
174
+ 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
175
+ 38, 31, nil, 31, nil, 31, 31, 31, 31, 31,
176
+ 31, 31, 31, 31, 31, 31, 31, 31, 25, 25,
177
+ 25, nil, 25, 25, 25, 25, 25, 25, 25, 25,
178
+ 25, 25, 25, 25, 25, 16, 16, 16, 36, 36,
179
+ 14, 14, 34, 34 ]
180
+
181
+ racc_action_pointer = [
182
+ nil, 20, 15, 18, nil, nil, nil, nil, nil, nil,
183
+ nil, nil, nil, nil, 84, nil, 77, nil, nil, nil,
184
+ nil, nil, nil, nil, nil, 66, -4, nil, nil, nil,
185
+ nil, 49, nil, nil, 84, nil, 82, 0, 32, -2,
186
+ nil, nil, nil, nil ]
187
+
188
+ racc_action_default = [
189
+ -2, -33, -1, -33, -21, -3, -22, -4, -23, -2,
190
+ -5, -24, -6, -25, -2, -26, -33, -18, -32, -19,
191
+ -27, -16, -17, -20, 44, -33, -10, -2, -11, -2,
192
+ -12, -13, -30, -28, -33, -7, -2, -33, -14, -15,
193
+ -31, -29, -9, -8 ]
194
+
195
+ racc_goto_table = [
196
+ 2, 26, 1, 37, nil, nil, nil, nil, nil, 25,
197
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
198
+ nil, nil, nil, 42, nil, nil, nil, 38, nil, 39 ]
199
+
200
+ racc_goto_check = [
201
+ 2, 7, 1, 8, nil, nil, nil, nil, nil, 2,
202
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
203
+ nil, nil, nil, 7, nil, nil, nil, 2, nil, 2 ]
204
+
205
+ racc_goto_pointer = [
206
+ nil, 2, 0, nil, nil, nil, nil, -13, -23, nil,
207
+ nil, nil ]
208
+
209
+ racc_goto_default = [
210
+ nil, nil, 31, 5, 7, 10, 12, nil, nil, 28,
211
+ 30, 20 ]
212
+
213
+ racc_token_table = {
214
+ false => 0,
215
+ Object.new => 1,
216
+ :BEGIN => 2,
217
+ :END => 3,
218
+ :IF => 4,
219
+ :ELSE => 5,
220
+ :AND => 6,
221
+ :OR => 7,
222
+ :CHARS => 8,
223
+ :QUOTED => 9,
224
+ :SPACES => 10,
225
+ :COMMA => 11,
226
+ :LPAREN => 12,
227
+ :RPAREN => 13,
228
+ :QUESTION => 14,
229
+ :ACTUAL_COMMENT => 15,
230
+ :EOL => 16,
231
+ :SUBSTITUTION => 17,
232
+ :PAREN_SUBSTITUTION => 18 }
233
+
234
+ racc_use_result_var = true
235
+
236
+ racc_nt_base = 19
237
+
238
+ Racc_arg = [
239
+ racc_action_table,
240
+ racc_action_check,
241
+ racc_action_default,
242
+ racc_action_pointer,
243
+ racc_goto_table,
244
+ racc_goto_check,
245
+ racc_goto_default,
246
+ racc_goto_pointer,
247
+ racc_nt_base,
248
+ racc_reduce_table,
249
+ racc_token_table,
250
+ racc_shift_n,
251
+ racc_reduce_n,
252
+ racc_use_result_var ]
253
+
254
+ Racc_token_to_s_table = [
255
+ '$end',
256
+ 'error',
257
+ 'BEGIN',
258
+ 'END',
259
+ 'IF',
260
+ 'ELSE',
261
+ 'AND',
262
+ 'OR',
263
+ 'CHARS',
264
+ 'QUOTED',
265
+ 'SPACES',
266
+ 'COMMA',
267
+ 'LPAREN',
268
+ 'RPAREN',
269
+ 'QUESTION',
270
+ 'ACTUAL_COMMENT',
271
+ 'EOL',
272
+ 'SUBSTITUTION',
273
+ 'PAREN_SUBSTITUTION',
274
+ '$start',
275
+ 'sql',
276
+ 'stmt_list',
277
+ 'stmt',
278
+ 'primary',
279
+ 'if_stmt',
280
+ 'begin_stmt',
281
+ 'sub_stmt',
282
+ 'else_stmt',
283
+ 'and_stmt',
284
+ 'or_stmt',
285
+ 'substitution']
286
+
287
+ Racc_debug_parser = false
288
+
289
+ ##### racc system variables end #####
290
+
291
+ # reduce 0 omitted
292
+
293
+ module_eval <<'.,.,', 'lib/twowaysql/parser.y', 8
294
+ def _reduce_1( val, _values, result )
295
+ result = RootNode.new( val[0] )
296
+ result
297
+ end
298
+ .,.,
299
+
300
+ module_eval <<'.,.,', 'lib/twowaysql/parser.y', 13
301
+ def _reduce_2( val, _values, result )
302
+ result = []
303
+ result
304
+ end
305
+ .,.,
306
+
307
+ module_eval <<'.,.,', 'lib/twowaysql/parser.y', 17
308
+ def _reduce_3( val, _values, result )
309
+ result.push val[1]
310
+ result
311
+ end
312
+ .,.,
313
+
314
+ # reduce 4 omitted
315
+
316
+ # reduce 5 omitted
317
+
318
+ # reduce 6 omitted
319
+
320
+ module_eval <<'.,.,', 'lib/twowaysql/parser.y', 26
321
+ def _reduce_7( val, _values, result )
322
+ result = BeginNode.new( val[1] )
323
+ result
324
+ end
325
+ .,.,
326
+
327
+ module_eval <<'.,.,', 'lib/twowaysql/parser.y', 31
328
+ def _reduce_8( val, _values, result )
329
+ result = IfNode.new( val[0], val[1], val[2] )
330
+ result
331
+ end
332
+ .,.,
333
+
334
+ module_eval <<'.,.,', 'lib/twowaysql/parser.y', 36
335
+ def _reduce_9( val, _values, result )
336
+ result = val[1]
337
+ result
338
+ end
339
+ .,.,
340
+
341
+ module_eval <<'.,.,', 'lib/twowaysql/parser.y', 40
342
+ def _reduce_10( val, _values, result )
343
+ result = nil
344
+ result
345
+ end
346
+ .,.,
347
+
348
+ # reduce 11 omitted
349
+
350
+ # reduce 12 omitted
351
+
352
+ # reduce 13 omitted
353
+
354
+ module_eval <<'.,.,', 'lib/twowaysql/parser.y', 49
355
+ def _reduce_14( val, _values, result )
356
+ result = SubStatementNode.new( val[0], val[1] )
357
+ result
358
+ end
359
+ .,.,
360
+
361
+ module_eval <<'.,.,', 'lib/twowaysql/parser.y', 54
362
+ def _reduce_15( val, _values, result )
363
+ result = SubStatementNode.new( val[0], val[1] )
364
+ result
365
+ end
366
+ .,.,
367
+
368
+ module_eval <<'.,.,', 'lib/twowaysql/parser.y', 59
369
+ def _reduce_16( val, _values, result )
370
+ result = LiteralNode.new( val[0] )
371
+ result
372
+ end
373
+ .,.,
374
+
375
+ module_eval <<'.,.,', 'lib/twowaysql/parser.y', 63
376
+ def _reduce_17( val, _values, result )
377
+ result = LiteralNode.new( val[0] )
378
+ result
379
+ end
380
+ .,.,
381
+
382
+ module_eval <<'.,.,', 'lib/twowaysql/parser.y', 67
383
+ def _reduce_18( val, _values, result )
384
+ result = LiteralNode.new( val[0] )
385
+ result
386
+ end
387
+ .,.,
388
+
389
+ module_eval <<'.,.,', 'lib/twowaysql/parser.y', 71
390
+ def _reduce_19( val, _values, result )
391
+ result = LiteralNode.new( val[0] )
392
+ result
393
+ end
394
+ .,.,
395
+
396
+ module_eval <<'.,.,', 'lib/twowaysql/parser.y', 75
397
+ def _reduce_20( val, _values, result )
398
+ result = LiteralNode.new( val[0] )
399
+ result
400
+ end
401
+ .,.,
402
+
403
+ module_eval <<'.,.,', 'lib/twowaysql/parser.y', 79
404
+ def _reduce_21( val, _values, result )
405
+ result = LiteralNode.new( val[0] )
406
+ result
407
+ end
408
+ .,.,
409
+
410
+ module_eval <<'.,.,', 'lib/twowaysql/parser.y', 83
411
+ def _reduce_22( val, _values, result )
412
+ result = LiteralNode.new( val[0] )
413
+ result
414
+ end
415
+ .,.,
416
+
417
+ module_eval <<'.,.,', 'lib/twowaysql/parser.y', 87
418
+ def _reduce_23( val, _values, result )
419
+ result = LiteralNode.new( val[0] )
420
+ result
421
+ end
422
+ .,.,
423
+
424
+ module_eval <<'.,.,', 'lib/twowaysql/parser.y', 92
425
+ def _reduce_24( val, _values, result )
426
+ @num_questions += 1
427
+ result = QuestionNode.new( @num_questions )
428
+ result
429
+ end
430
+ .,.,
431
+
432
+ module_eval <<'.,.,', 'lib/twowaysql/parser.y', 96
433
+ def _reduce_25( val, _values, result )
434
+ result = CommentNode.new( val[0] )
435
+ result
436
+ end
437
+ .,.,
438
+
439
+ module_eval <<'.,.,', 'lib/twowaysql/parser.y', 100
440
+ def _reduce_26( val, _values, result )
441
+ result = EolNode.new
442
+ result
443
+ end
444
+ .,.,
445
+
446
+ # reduce 27 omitted
447
+
448
+ module_eval <<'.,.,', 'lib/twowaysql/parser.y', 106
449
+ def _reduce_28( val, _values, result )
450
+ result = SubstitutionNode.new( val[0] )
451
+ result
452
+ end
453
+ .,.,
454
+
455
+ module_eval <<'.,.,', 'lib/twowaysql/parser.y', 110
456
+ def _reduce_29( val, _values, result )
457
+ result = SubstitutionNode.new( val[0] )
458
+ result
459
+ end
460
+ .,.,
461
+
462
+ module_eval <<'.,.,', 'lib/twowaysql/parser.y', 114
463
+ def _reduce_30( val, _values, result )
464
+ result = SubstitutionNode.new( val[0] )
465
+ result
466
+ end
467
+ .,.,
468
+
469
+ module_eval <<'.,.,', 'lib/twowaysql/parser.y', 118
470
+ def _reduce_31( val, _values, result )
471
+ result = SubstitutionNode.new( val[0] )
472
+ result
473
+ end
474
+ .,.,
475
+
476
+ module_eval <<'.,.,', 'lib/twowaysql/parser.y', 122
477
+ def _reduce_32( val, _values, result )
478
+ result = ParenSubstitutionNode.new( val[0] )
479
+ result
480
+ end
481
+ .,.,
482
+
483
+ def _reduce_none( val, _values, result )
484
+ result
485
+ end
486
+
487
+ end # class Parser
488
+
489
+ end # module TwoWaySQL
@@ -0,0 +1,226 @@
1
+ class TwoWaySQL::Parser
2
+
3
+ rule
4
+
5
+ sql : stmt_list
6
+ {
7
+ result = RootNode.new( val[0] )
8
+ }
9
+
10
+ stmt_list :
11
+ {
12
+ result = []
13
+ }
14
+ | stmt_list stmt
15
+ {
16
+ result.push val[1]
17
+ }
18
+
19
+ stmt : primary
20
+ | if_stmt
21
+ | begin_stmt
22
+
23
+ begin_stmt : BEGIN stmt_list END
24
+ {
25
+ result = BeginNode.new( val[1] )
26
+ }
27
+
28
+ if_stmt : IF sub_stmt else_stmt END
29
+ {
30
+ result = IfNode.new( val[0], val[1], val[2] )
31
+ }
32
+
33
+ else_stmt : ELSE sub_stmt
34
+ {
35
+ result = val[1]
36
+ }
37
+ |
38
+ {
39
+ result = nil
40
+ }
41
+
42
+ sub_stmt : and_stmt
43
+ | or_stmt
44
+ | stmt_list
45
+
46
+ and_stmt : AND stmt_list
47
+ {
48
+ result = SubStatementNode.new( val[0], val[1] )
49
+ }
50
+
51
+ or_stmt : OR stmt_list
52
+ {
53
+ result = SubStatementNode.new( val[0], val[1] )
54
+ }
55
+
56
+ primary : CHARS
57
+ {
58
+ result = LiteralNode.new( val[0] )
59
+ }
60
+ | QUOTED
61
+ {
62
+ result = LiteralNode.new( val[0] )
63
+ }
64
+ | AND
65
+ {
66
+ result = LiteralNode.new( val[0] )
67
+ }
68
+ | OR
69
+ {
70
+ result = LiteralNode.new( val[0] )
71
+ }
72
+ | SPACES
73
+ {
74
+ result = LiteralNode.new( val[0] )
75
+ }
76
+ | COMMA
77
+ {
78
+ result = LiteralNode.new( val[0] )
79
+ }
80
+ | LPAREN
81
+ {
82
+ result = LiteralNode.new( val[0] )
83
+ }
84
+ | RPAREN
85
+ {
86
+ result = LiteralNode.new( val[0] )
87
+ }
88
+ | QUESTION
89
+ {
90
+ @num_questions += 1
91
+ result = QuestionNode.new( @num_questions )
92
+ }
93
+ | ACTUAL_COMMENT
94
+ {
95
+ result = CommentNode.new( val[0] )
96
+ }
97
+ | EOL
98
+ {
99
+ result = EolNode.new
100
+ }
101
+ | substitution
102
+
103
+ substitution : SUBSTITUTION QUOTED
104
+ {
105
+ result = SubstitutionNode.new( val[0] )
106
+ }
107
+ | SUBSTITUTION SPACES QUOTED
108
+ {
109
+ result = SubstitutionNode.new( val[0] )
110
+ }
111
+ | SUBSTITUTION CHARS
112
+ {
113
+ result = SubstitutionNode.new( val[0] )
114
+ }
115
+ | SUBSTITUTION SPACES CHARS
116
+ {
117
+ result = SubstitutionNode.new( val[0] )
118
+ }
119
+ | PAREN_SUBSTITUTION
120
+ {
121
+ result = ParenSubstitutionNode.new( val[0] )
122
+ }
123
+
124
+ end
125
+
126
+
127
+ ---- inner
128
+
129
+ require 'strscan'
130
+
131
+ def initialize(opts={})
132
+ opts = {
133
+ :debug => true,
134
+ :preserve_space => true,
135
+ :preserve_comment => true,
136
+ :preserve_eol => true
137
+ }.merge(opts)
138
+ @yydebug = opts[:debug]
139
+ @preserve_space = opts[:preserve_space]
140
+ @preserve_comment = opts[:preserve_comment]
141
+ @preserve_eol = opts[:preserve_eol]
142
+ @num_questions = 0
143
+ end
144
+
145
+ BEGIN_SUBSTITUTION = '(\/|\#)\*([^\*]+)\*\1'
146
+ PAREN_EXAMPLE = '\([^\)]+\)'
147
+ SUBSTITUTION_PATTERN = /\A#{BEGIN_SUBSTITUTION}\s*/
148
+ PAREN_SUBSTITUTION_PATTERN = /\A#{BEGIN_SUBSTITUTION}\s*#{PAREN_EXAMPLE}/
149
+
150
+ CONDITIONAL_PATTERN = /\A(\/|\#)\*(IF)\s+([^\*]+)\s*\*\1/
151
+ BEGIN_END_PATTERN = /\A(\/|\#)\*(BEGIN|END)\s*\*\1/
152
+ QUOTED_STRING_PATTERN = /\A(\'(?:[^\']+|\'\')*\')/ ## quoted string
153
+ SPLIT_TOKEN_PATTERN = /\A(\S+?)(?=\s*(?:(?:\/|\#)\*|-{2,}|\(|\)|\,))/ ## stop on delimiters --,/*,#*,',',(,)
154
+ ELSE_PATTERN = /\A\-{2,}\s*ELSE\s*/
155
+ AND_PATTERN = /\A(\s*AND\s+)/
156
+ OR_PATTERN = /\A(\s*OR\s+)/
157
+ LITERAL_PATTERN = /\A([^;\s]+)/
158
+ SPACES_PATTERN = /\A(\s+)/
159
+ QUESTION_PATTERN = /\A\?/
160
+ COMMA_PATTERN = /\A\,/
161
+ LPAREN_PATTERN = /\A\(/
162
+ RPAREN_PATTERN = /\A\)/
163
+ ACTUAL_COMMENT_PATTERN = /\A(\/|\#)\*\s+(.+)\s*\*\1/ ## start with spaces
164
+ SEMICOLON_AT_INPUT_END_PATTERN = /\A\;\s*\Z/
165
+ UNMATCHED_COMMENT_START_PATTERN = /\A(?:(?:\/|\#)\*)/
166
+
167
+
168
+ def parse( io )
169
+ @q = []
170
+ io.each do |line|
171
+ s = StringScanner.new(line.rstrip)
172
+ until s.eos? do
173
+ case
174
+ when s.scan(AND_PATTERN)
175
+ @q.push [ :AND, s[1] ]
176
+ when s.scan(OR_PATTERN)
177
+ @q.push [ :OR, s[1] ]
178
+ when s.scan(SPACES_PATTERN)
179
+ @q.push [ :SPACES, s[1] ] if @preserve_space
180
+ when s.scan(QUESTION_PATTERN)
181
+ @q.push [ :QUESTION, nil ]
182
+ when s.scan(COMMA_PATTERN)
183
+ @q.push [ :COMMA, ',' ]
184
+ when s.scan(LPAREN_PATTERN)
185
+ @q.push [ :LPAREN, '(' ]
186
+ when s.scan(RPAREN_PATTERN)
187
+ @q.push [ :RPAREN, ')' ]
188
+ when s.scan(ELSE_PATTERN)
189
+ @q.push [ :ELSE, nil ]
190
+ when s.scan(ACTUAL_COMMENT_PATTERN)
191
+ @q.push [ :ACTUAL_COMMENT, s[2] ] if @preserve_comment
192
+ when s.scan(BEGIN_END_PATTERN)
193
+ @q.push [ s[2].intern, nil ]
194
+ when s.scan(CONDITIONAL_PATTERN)
195
+ @q.push [ s[2].intern, s[3] ]
196
+ when s.scan(PAREN_SUBSTITUTION_PATTERN)
197
+ @q.push [ :PAREN_SUBSTITUTION, s[2] ]
198
+ when s.scan(SUBSTITUTION_PATTERN)
199
+ @q.push [ :SUBSTITUTION, s[2] ]
200
+ when s.scan(QUOTED_STRING_PATTERN)
201
+ @q.push [ :QUOTED, s[1] ]
202
+ when s.scan(SPLIT_TOKEN_PATTERN)
203
+ @q.push [ :CHARS, s[1] ]
204
+ when s.scan(UNMATCHED_COMMENT_START_PATTERN) ## unmatched comment start, '/*','#*'
205
+ raise Racc::ParseError, "## unmatched comment. cannot parse [#{s.rest}]"
206
+ when s.scan(LITERAL_PATTERN) ## other string token
207
+ @q.push [ :CHARS, s[1] ]
208
+ when s.scan(SEMICOLON_AT_INPUT_END_PATTERN)
209
+ #drop semicolon at input end
210
+ else
211
+ raise Racc::ParseError, "## cannot parse [#{s.rest}]"
212
+ end
213
+ end
214
+
215
+ @q.push [ :EOL, nil ] if @preserve_eol
216
+ end
217
+
218
+ @q.push [ false, nil ]
219
+
220
+ ## cal racc's private parse method
221
+ do_parse
222
+ end
223
+
224
+ def next_token
225
+ @q.shift
226
+ end