rlsm 0.2.3 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -12,6 +12,13 @@ lib/rlsm/monkey_patching.rb
12
12
  lib/rlsm/monoid.rb
13
13
  lib/rlsm/monoid_db.rb
14
14
  lib/rlsm/regexp.rb
15
+ lib/rlsm/regexp_nodes/concat.rb
16
+ lib/rlsm/regexp_nodes/primexp.rb
17
+ lib/rlsm/regexp_nodes/renodes.rb
18
+ lib/rlsm/regexp_nodes/star.rb
19
+ lib/rlsm/regexp_nodes/union.rb
20
+ lib/smon/commands/db_find.rb
21
+ lib/smon/commands/db_stat.rb
15
22
  lib/smon/commands/exit.rb
16
23
  lib/smon/commands/help.rb
17
24
  lib/smon/commands/intro.rb
@@ -20,5 +27,9 @@ lib/smon/commands/quit.rb
20
27
  lib/smon/commands/regexp.rb
21
28
  lib/smon/commands/reload.rb
22
29
  lib/smon/commands/show.rb
30
+ lib/smon/presenter.rb
31
+ lib/smon/presenter/txt_presenter.rb
23
32
  lib/smon/smon.rb
24
- test/test_rlsm.rb
33
+ test/dfa_spec.rb
34
+ test/monoid_spec.rb
35
+ test/regexp_spec.rb
@@ -35,5 +35,5 @@ require "mgen"
35
35
  require "monoid_db"
36
36
 
37
37
  module RLSM
38
- VERSION = "0.2.3"
38
+ VERSION = "0.2.4"
39
39
  end
@@ -29,6 +29,7 @@
29
29
  require File.join(File.dirname(__FILE__), 'monkey_patching')
30
30
  require File.join(File.dirname(__FILE__), 'monoid')
31
31
  require File.join(File.dirname(__FILE__), 'regexp')
32
+ require File.join(File.dirname(__FILE__), 'exceptions.rb')
32
33
 
33
34
  module RLSM
34
35
  class DFA
@@ -453,13 +454,14 @@ module RLSM
453
454
 
454
455
  matr.map! do |row|
455
456
  row.each_with_index do |re,j|
456
- row[j] = re + ri[j]
457
+ row[j] = re + row[i]*ri[j]
457
458
  end
458
459
 
459
460
  row[i] = RLSM::RegExp.new
460
461
 
461
462
  row
462
463
  end
464
+
463
465
  end
464
466
 
465
467
  #Examine now the last remaining first row (irritating...)
@@ -514,8 +516,15 @@ module RLSM
514
516
 
515
517
  #Returns a string represantation
516
518
  def to_s
517
- @states.map { |state| state.to_s }.join("\n")
519
+ str = "\t| #{@alphabet.join(' | ')} \n"
520
+ str += '-'*(str.length+7) + "\n"
521
+ str + @states.map { |state| state.to_s }.join("\n")
522
+ end
523
+
524
+ def inspect
525
+ "<#{self.class}: #{@states.map {|c| c.label }.join(', ') }"
518
526
  end
527
+
519
528
 
520
529
 
521
530
  protected
@@ -678,8 +687,8 @@ module RLSM
678
687
  str = ''
679
688
  str += '-> ' if initial?
680
689
  str += '* ' if final?
681
- str += @label.to_s + ': '
682
- str += @trans.to_a.map { |c,s| c+' -> '+s.label.to_s }.join('; ')
690
+ str += @label.to_s + "\t| "
691
+ str += @dfa.alphabet.map { |c| process(c) ? process(c).label : ' ' }.join(' | ')
683
692
 
684
693
  str
685
694
  end
@@ -28,6 +28,7 @@
28
28
 
29
29
  require File.join(File.dirname(__FILE__), 'monkey_patching')
30
30
  require File.join(File.dirname(__FILE__), 'dfa')
31
+ require File.join(File.dirname(__FILE__), 'exceptions.rb')
31
32
 
32
33
  # A Monoid is a set of elements with an associative binary operation and a neutral element.
33
34
  module RLSM
@@ -371,9 +372,9 @@ class Monoid
371
372
 
372
373
  #Returns a DFA with the monoid elements as states, the neutral element as initial state and transitions given by the binary operation. The argument gives the final states. If the monoid is syntactic, the finals must be a disjunctive subset. If no argument is given in this case, the smallest disjunctive subset is used.
373
374
  def to_dfa(finals = [])
374
- alph = @names.values_at(generating_subset)
375
+ alph = @names.values_at(*generating_subset)
375
376
  states = @names.clone
376
- inital = @names.first
377
+ initial = @names.first
377
378
 
378
379
  if syntactic?
379
380
  if finals.empty?
@@ -387,10 +388,10 @@ class Monoid
387
388
 
388
389
  trans = []
389
390
  alph.each do |char|
390
- @names.each { |s1| trans << [char, s1, self[s1,char]] }
391
+ @names.each { |s1| trans << [char, s1, @names[self[s1,char]]] }
391
392
  end
392
393
 
393
- RLSM::DFA.new alph, states, initial, finals, trans
394
+ RLSM::DFA.new alph, states, initial, finals.map {|c| @names[c] }, trans
394
395
  end
395
396
 
396
397
  private
@@ -489,11 +490,11 @@ class Monoid
489
490
  if names and names.class == Array and names.size == @order
490
491
  @names = names
491
492
  else
492
- #Make a guess, works if convention is followed.
493
+ #Make a guess, works if the convention that the first row belongs to the neutral element is followed.
493
494
  @names = @bo.flatten.uniq.clone
494
495
  end
495
496
 
496
- @bo = (@bo.flatten.map { |e| @names.index(e) })/@order
497
+ @bo = (@bo.flatten.map { |e| @names.include?(e) ? @names.index(e) : e })/@order
497
498
  end
498
499
 
499
500
  def _check_form_of_binary_operation
@@ -110,7 +110,7 @@ SQL
110
110
  q = "SELECT binop FROM monoids"
111
111
 
112
112
  where = Columns.map do |col|
113
- params[col] ? (col.to_s + " = " + params[col]) : nil
113
+ params[col] ? ("#{col.to_s} = #{params[col]}") : nil
114
114
  end.compact.join(" AND ")
115
115
 
116
116
  if where.length > 0
@@ -26,23 +26,22 @@
26
26
  #
27
27
 
28
28
  require File.join(File.dirname(__FILE__), 'monkey_patching')
29
+ require File.join(File.dirname(__FILE__), 'exceptions.rb')
30
+ require File.join(File.dirname(__FILE__), 'regexp_nodes', 'renodes')
31
+ require File.join(File.dirname(__FILE__), 'dfa')
29
32
 
30
33
  module RLSM
31
34
  class RegExp
35
+ include RLSM::RENodes
36
+
32
37
  #Creates a new RegExp from a string description. Metacharacters are
33
38
  # & * | ( )
34
39
  #Here & is the empty word and an empty string represents the empty set.
35
- def initialize(str = "")
40
+ def initialize(desc = "")
36
41
  #Is the argument a well formed RegExp?
37
- _well_formed?(str)
42
+ _well_formed?(desc)
38
43
 
39
- #More than one & or * in a row is useless
40
- re = str.squeeze('&*')
41
-
42
- #* on a & is &
43
- re = re.gsub('&*', '&')
44
-
45
- @re = NodeFactory.new_node(nil, re)
44
+ @re = RLSM::RENodes.new(desc)
46
45
  end
47
46
 
48
47
  #--
@@ -55,7 +54,7 @@ module RLSM
55
54
  #A double star is also useless
56
55
  return if empty? or lambda? or (@re.class == Star)
57
56
  str = '(' + to_s + ')*'
58
- @re = NodeFactory.new_node(nil, str)
57
+ @re = RLSM::RENodes.new(str)
59
58
 
60
59
  #Unset the str rep
61
60
  @re_str = nil
@@ -142,7 +141,7 @@ module RLSM
142
141
  end
143
142
  end
144
143
 
145
- tmp_re = NodeFactory.new_node(nil, rre)
144
+ tmp_re = RLSM::RENodes.new(rre)
146
145
 
147
146
  #Step 2a: Construct a DFA representation of this new regexp
148
147
  #Step 2b: reverse the substitution (yields (maybe) a NFA)
@@ -213,11 +212,8 @@ module RLSM
213
212
  #parantheses must be balanced, somthing like |) or *a or (| isn't allowed
214
213
  #1 balanced parenthesis
215
214
  state = 0
216
- count = Hash.new(0)
217
- count['('] = 1
218
- count[')'] = -1
219
215
  str.each_char do |c|
220
- state += count[c]
216
+ state += RLSM::RENodes::PCount[c]
221
217
  end
222
218
 
223
219
  if state != 0
@@ -229,365 +225,5 @@ module RLSM
229
225
  raise RegExpException, "Bad character sequence #{$&} found in #{str}"
230
226
  end
231
227
  end
232
-
233
- class PrimExp
234
- def initialize(parent, str)
235
- @parent = parent
236
- if str == '&' or str == ['&']
237
- @content = '&'
238
- @null = true
239
- else
240
- @content = str.reject { |c| c == '&' }
241
- @null = false
242
- end
243
- end
244
-
245
- def null?
246
- @null
247
- end
248
-
249
- def first
250
- @null ? [] : @content[0,1]
251
- end
252
-
253
- def last
254
- @null ? [] : @content[-1,1]
255
- end
256
-
257
- def follow
258
- res = []
259
-
260
- (1...@content.length).each do |i|
261
- res << [@content[i-1,1], @content[i,1]]
262
- end
263
-
264
- res
265
- end
266
-
267
- def to_s
268
- @content.to_s
269
- end
270
-
271
- def lambda?
272
- @null
273
- end
274
-
275
- def empty?
276
- @content == '' or @content == []
277
- end
278
- end
279
-
280
- class Star
281
- def initialize(parent, str)
282
- @parent = parent
283
- @child = NodeFactory.new_node(self, str[(0..-2)])
284
- end
285
-
286
- def null?
287
- true
288
- end
289
-
290
- def first
291
- @child.first
292
- end
293
-
294
- def last
295
- @child.last
296
- end
297
-
298
- def follow
299
- res = @child.follow
300
-
301
- #Cross of last and first
302
- first.each do |f|
303
- last.each do |l|
304
- res << [l,f]
305
- end
306
- end
307
-
308
- res
309
- end
310
-
311
- def to_s
312
- if @child.class == PrimExp and @child.to_s.length == 1
313
- return "#{@child.to_s}*"
314
- else
315
- return "(#{@child.to_s})*"
316
- end
317
- end
318
-
319
- def lambda?
320
- false
321
- end
322
-
323
- def empty?
324
- false
325
- end
326
- end
327
-
328
- class Union
329
- def initialize(parent, str)
330
- @parent = parent
331
- @childs = _split(str).map do |substr|
332
- NodeFactory.new_node(self, substr)
333
- end
334
- end
335
-
336
- def null?
337
- @childs.any? { |child| child.null? }
338
- end
339
-
340
- def first
341
- res = []
342
- @childs.each do |child|
343
- child.first.each do |f|
344
- res << f
345
- end
346
- end
347
-
348
- res
349
- end
350
-
351
- def last
352
- res = []
353
- @childs.each do |child|
354
- child.last.each do |l|
355
- res << l
356
- end
357
- end
358
-
359
- res
360
- end
361
-
362
- def follow
363
- res = []
364
- @childs.each do |child|
365
- child.follow.each do |f|
366
- res << f
367
- end
368
- end
369
-
370
- res
371
- end
372
-
373
- def to_s
374
- if @parent.nil? or @parent.class == Union or @paarent.class == Star
375
- return @childs.map { |child| child.to_s }.join('|')
376
- else
377
- return '(' + @childs.map { |child| child.to_s }.join('|') + ')'
378
- end
379
- end
380
-
381
- def lambda?
382
- false
383
- end
384
-
385
- def empty?
386
- false
387
- end
388
-
389
- private
390
- def _split(str)
391
- state = 0
392
- count = Hash.new(0)
393
- count['('] = 1
394
- count[')'] = -1
395
-
396
- res = [[]]
397
-
398
- str.each_char do |c|
399
- state += count[c]
400
- if c == '|' and state == 0
401
- res << []
402
- else
403
- res.last << c
404
- end
405
- end
406
-
407
- res#.map { |substr| substr.join }
408
- end
409
- end
410
-
411
- class Concat
412
- def initialize(parent, str)
413
- @parent = parent
414
- @childs = _split(str).map do |substr|
415
- NodeFactory.new_node(self, substr)
416
- end.reject { |child| child.lambda? }
417
- end
418
-
419
- def null?
420
- @childs.all? { |child| child.null? }
421
- end
422
-
423
- def first
424
- res = []
425
- @childs.each do |child|
426
- child.first.each do |f|
427
- res << f
428
- end
429
-
430
- break unless child.null?
431
- end
432
-
433
- res
434
- end
435
-
436
- def last
437
- res = []
438
- @childs.reverse.each do |child|
439
- child.last.each do |f|
440
- res << f
441
- end
442
-
443
- break unless child.null?
444
- end
445
-
446
- res
447
- end
448
-
449
- def follow
450
- res = []
451
-
452
- @childs.each do |child|
453
- child.follow.each do |f|
454
- res << f
455
- end
456
- end
457
-
458
- (1...@childs.size).each do |i|
459
- @childs[i-1].last.each do |l|
460
- @childs[(i..-1)].each do |ch|
461
- ch.first.each do |f|
462
- res << [l,f]
463
- end
464
-
465
- break unless ch.null?
466
- end
467
- end
468
- end
469
-
470
- res
471
- end
472
-
473
- def to_s
474
- @childs.map { |child| child.to_s }.join
475
- end
476
-
477
- def lambda?
478
- false
479
- end
480
-
481
- def empty?
482
- false
483
- end
484
-
485
- private
486
- def _split(str)
487
- state = 0
488
- count = Hash.new(0)
489
- count['('] = 1
490
- count[')'] = -1
491
-
492
- res = [[]]
493
- previous = nil
494
- str.each_char do |c|
495
- state += count[c]
496
-
497
- if state == 1 and c == '('
498
- res << []
499
- res.last << c
500
- elsif state == 0 and c == '*'
501
- if previous == ')'
502
- res[-2] << c
503
- else
504
- res << [res.last.pop, c]
505
- res << []
506
- end
507
- elsif state == 0 and c == ')'
508
- res.last << c
509
- res << []
510
- else
511
- res.last << c
512
- end
513
-
514
- previous = c
515
- end
516
-
517
- res.select { |subarr| subarr.size > 0 }#.map { |substr| substr.join }
518
- end
519
- end
520
-
521
- class NodeFactory
522
- def self.new_node(parent, arg)
523
-
524
- #Remove parentheses
525
- str = arg.dup
526
- while sp(str)
527
- str = str[(1..-2)]
528
- end
529
- #puts "Processing: #{arg} from #{parent.class}"
530
- #Choose the right node type
531
- if prim?(str)
532
- return PrimExp.new(parent, str)
533
- elsif star?(str)
534
- return Star.new(parent, str)
535
- elsif union?(str)
536
- return Union.new(parent, str)
537
- else
538
- return Concat.new(parent, str)
539
- end
540
-
541
- end
542
-
543
- private
544
- def self.sp(str)
545
- if str[0,1].include? '(' and str[-1,1].include? ')'
546
- state = 0
547
- l = 0
548
- count = Hash.new(0)
549
- count['('] = 1
550
- count[')'] = -1
551
-
552
- str.each_char do |c|
553
- state += count[c]
554
- l += 1
555
- break if state == 0
556
- end
557
-
558
- return true if str.length == l
559
- end
560
-
561
- false
562
- end
563
-
564
- def self.prim?(str)
565
- not ['(', ')', '|', '*'].any? { |c| str.include? c }
566
- end
567
-
568
- def self.star?(str)
569
- if str[-1,1].include? '*'
570
- return true if sp(str[(0..-2)]) #something like (....)*
571
- return true if str.length == 2 #something like a*
572
- end
573
-
574
- false
575
- end
576
-
577
- def self.union?(str)
578
- state = 0
579
- count = Hash.new(0)
580
- count['('] = 1
581
- count[')'] = -1
582
-
583
- str.each_char do |c|
584
- state += count[c]
585
-
586
- return true if c == '|' and state == 0
587
- end
588
-
589
- false
590
- end
591
- end
592
228
  end
593
229
  end