twowaysql 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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