Sentence.expand_syntax refined.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13114 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
1d23c250f0
commit
cf82149d21
@ -33,7 +33,7 @@
|
|||||||
# The third argument, 2, limits derivation to restrict results finitely.
|
# The third argument, 2, limits derivation to restrict results finitely.
|
||||||
#
|
#
|
||||||
# Some arithmetic expressions including parenthesis can be generated as follows.
|
# Some arithmetic expressions including parenthesis can be generated as follows.
|
||||||
#
|
#
|
||||||
# syntax = {
|
# syntax = {
|
||||||
# :factor => [["n"],
|
# :factor => [["n"],
|
||||||
# ["(", :exp, ")"]],
|
# ["(", :exp, ")"]],
|
||||||
@ -160,10 +160,10 @@ class Sentence
|
|||||||
|
|
||||||
# returns the number of top level elements.
|
# returns the number of top level elements.
|
||||||
#
|
#
|
||||||
# Sentence.new(%w[foo bar]).length
|
# Sentence.new(%w[foo bar]).length
|
||||||
# #=> 2
|
# #=> 2
|
||||||
#
|
#
|
||||||
# Sentence(%w[2 * 7], "+", %w[3 * 5]).length
|
# Sentence(%w[2 * 7], "+", %w[3 * 5]).length
|
||||||
# #=> 3
|
# #=> 3
|
||||||
#
|
#
|
||||||
def length
|
def length
|
||||||
@ -310,7 +310,7 @@ class Sentence
|
|||||||
# #<Sentence: "n">
|
# #<Sentence: "n">
|
||||||
# #<Sentence: ("n") "+" ("n")>
|
# #<Sentence: ("n") "+" ("n")>
|
||||||
# #<Sentence: ("n") "*" ("n")>
|
# #<Sentence: ("n") "*" ("n")>
|
||||||
#
|
#
|
||||||
# Sentence.each({
|
# Sentence.each({
|
||||||
# :exp => [["n"],
|
# :exp => [["n"],
|
||||||
# [:exp, "+", :exp],
|
# [:exp, "+", :exp],
|
||||||
@ -336,33 +336,47 @@ class Sentence
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Sentence.expand_syntax returns an expanded syntax:
|
# Sentence.expand_syntax returns an expanded syntax:
|
||||||
# * no underivable rule
|
# * No rule derives to empty sequence
|
||||||
# * no rule which derives only to empty sequence indirectly
|
# * Underivable rule simplified
|
||||||
# * no rule which is derivable to empty and non-empty
|
# * No channel rule
|
||||||
# * no channel rule
|
# * Symbols which has zero or one choices are not appered in rhs.
|
||||||
#
|
#
|
||||||
# Note that the rules which can derive empty and non-empty
|
# Note that the rules which can derive empty and non-empty
|
||||||
# sequences are modified to derive only non-empty sequences.
|
# sequences are modified to derive only non-empty sequences.
|
||||||
#
|
#
|
||||||
# Sentence.expand_syntax({
|
# Sentence.expand_syntax({
|
||||||
# :underivable => [[:underivable]],
|
# :underivable1 => [],
|
||||||
# :just_empty1 => [[]],
|
# :underivable2 => [[:underivable1]],
|
||||||
# :just_empty2 => [[:just_empty1, :just_empty1]],
|
# :underivable3 => [[:underivable3]],
|
||||||
|
# :empty_only1 => [[]],
|
||||||
|
# :empty_only2 => [[:just_empty1, :just_empty1]],
|
||||||
# :empty_or_not => [[], ["foo"]],
|
# :empty_or_not => [[], ["foo"]],
|
||||||
# :empty_or_not_2 => [[:empty_or_not, :empty_or_not]],
|
# :empty_or_not_2 => [[:empty_or_not, :empty_or_not]],
|
||||||
# :data => [["a", "b"], ["c", "d"]],
|
# :empty_or_not_3 => [[:empty_or_not, :empty_or_not, :empty_or_not]],
|
||||||
# :channel => [[:data]],
|
# :empty_or_not_4 => [[:empty_or_not_2, :empty_or_not_2]],
|
||||||
# })
|
# :channel1 => [[:channeled_data]],
|
||||||
|
# :channeled_data => [["a", "b"], ["c", "d"]],
|
||||||
|
# :single_choice => [["single", "choice"]],
|
||||||
|
# :single_choice_2 => [[:single_choice, :single_choice]],
|
||||||
|
# })
|
||||||
# #=>
|
# #=>
|
||||||
# {:channel=>[["a", "b"], ["c", "d"]],
|
# {
|
||||||
# :data=>[["a", "b"], ["c", "d"]],
|
# :underivable1=>[], # underivable rules are simplified to [].
|
||||||
# :empty_or_not=>[["foo"]],
|
# :underivable2=>[],
|
||||||
# :empty_or_not_2=>[[], ["foo"], ["foo", "foo"]],
|
# :underivable3=>[],
|
||||||
# :just_empty1=>[],
|
# :empty_only1=>[], # derivation to empty sequence are removed.
|
||||||
# :just_empty2=>[]}
|
# :empty_only2=>[],
|
||||||
|
# :empty_or_not=>[["foo"]], # empty sequences are removed too.
|
||||||
|
# :empty_or_not_2=>[["foo"], ["foo", "foo"]],
|
||||||
|
# :empty_or_not_3=>[["foo"], ["foo", "foo"], ["foo", "foo", "foo"]],
|
||||||
|
# :empty_or_not_4=> [["foo"], ["foo", "foo"], [:empty_or_not_2, :empty_or_not_2]],
|
||||||
|
# :channel1=>[["a", "b"], ["c", "d"]], # channel rules are removed.
|
||||||
|
# :channeled_data=>[["a", "b"], ["c", "d"]],
|
||||||
|
# :single_choice=>[["single", "choice"]], # single choice rules are expanded.
|
||||||
|
# :single_choice_2=>[["single", "choice", "single", "choice"]],
|
||||||
|
# }
|
||||||
#
|
#
|
||||||
#
|
# Sentence.expand_syntax({
|
||||||
# Sentence.expand_syntax({
|
|
||||||
# :factor => [["n"],
|
# :factor => [["n"],
|
||||||
# ["(", :exp, ")"]],
|
# ["(", :exp, ")"]],
|
||||||
# :term => [[:factor],
|
# :term => [[:factor],
|
||||||
@ -406,16 +420,16 @@ class Sentence
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.expand_syntax(syntax)
|
def self.expand_syntax(syntax)
|
||||||
syntax = remove_underivable_rules(syntax)
|
syntax = simplify_underivable_rules(syntax)
|
||||||
syntax = expand_justempty_rules(syntax)
|
syntax = simplify_emptyonly_rules(syntax)
|
||||||
syntax = remove_emptyable_rules(syntax)
|
syntax = make_rules_no_empseq(syntax)
|
||||||
syntax = expand_channel_rules(syntax)
|
syntax = expand_channel_rules(syntax)
|
||||||
|
|
||||||
syntax = expand_noalt_rules(syntax)
|
syntax = expand_noalt_rules(syntax)
|
||||||
syntax = reorder_rules(syntax)
|
syntax = reorder_rules(syntax)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.remove_underivable_rules(syntax)
|
def self.simplify_underivable_rules(syntax)
|
||||||
deribable_syms = {}
|
deribable_syms = {}
|
||||||
changed = true
|
changed = true
|
||||||
while changed
|
while changed
|
||||||
@ -433,24 +447,27 @@ class Sentence
|
|||||||
end
|
end
|
||||||
result = {}
|
result = {}
|
||||||
syntax.each {|sym, rules|
|
syntax.each {|sym, rules|
|
||||||
next if !deribable_syms[sym]
|
if deribable_syms[sym]
|
||||||
rules2 = []
|
rules2 = []
|
||||||
rules.each {|rhs|
|
rules.each {|rhs|
|
||||||
rules2 << rhs if rhs.all? {|e| String === e || deribable_syms[e] }
|
rules2 << rhs if rhs.all? {|e| String === e || deribable_syms[e] }
|
||||||
}
|
}
|
||||||
result[sym] = rules2.uniq
|
result[sym] = rules2.uniq
|
||||||
|
else
|
||||||
|
result[sym] = []
|
||||||
|
end
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.expand_justempty_rules(syntax)
|
def self.simplify_emptyonly_rules(syntax)
|
||||||
justempty_syms = {}
|
justempty_syms = {}
|
||||||
changed = true
|
changed = true
|
||||||
while changed
|
while changed
|
||||||
changed = false
|
changed = false
|
||||||
syntax.each {|sym, rules|
|
syntax.each {|sym, rules|
|
||||||
next if justempty_syms[sym]
|
next if justempty_syms[sym]
|
||||||
if rules.all? {|rhs| rhs.all? {|e| justempty_syms[e] } }
|
if !rules.empty? && rules.all? {|rhs| rhs.all? {|e| justempty_syms[e] } }
|
||||||
justempty_syms[sym] = true
|
justempty_syms[sym] = true
|
||||||
changed = true
|
changed = true
|
||||||
end
|
end
|
||||||
@ -473,21 +490,22 @@ class Sentence
|
|||||||
yield rhs
|
yield rhs
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
butfirst = rhs[1..-1]
|
rest = rhs.dup
|
||||||
if emptyable_syms[rhs[0]]
|
first = rest.shift
|
||||||
expand_emptyable_syms(butfirst, emptyable_syms) {|rhs2|
|
if emptyable_syms[first]
|
||||||
yield [rhs[0]] + rhs2
|
expand_emptyable_syms(rest, emptyable_syms) {|rhs2|
|
||||||
|
yield [first] + rhs2
|
||||||
yield rhs2
|
yield rhs2
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
expand_emptyable_syms(butfirst, emptyable_syms) {|rhs2|
|
expand_emptyable_syms(rest, emptyable_syms) {|rhs2|
|
||||||
yield [rhs[0]] + rhs2
|
yield [first] + rhs2
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.remove_emptyable_rules(syntax)
|
def self.make_rules_no_empseq(syntax)
|
||||||
emptyable_syms = {}
|
emptyable_syms = {}
|
||||||
changed = true
|
changed = true
|
||||||
while changed
|
while changed
|
||||||
@ -508,6 +526,7 @@ class Sentence
|
|||||||
rules2 = []
|
rules2 = []
|
||||||
rules.each {|rhs|
|
rules.each {|rhs|
|
||||||
expand_emptyable_syms(rhs, emptyable_syms) {|rhs2|
|
expand_emptyable_syms(rhs, emptyable_syms) {|rhs2|
|
||||||
|
next if rhs2.empty?
|
||||||
rules2 << rhs2
|
rules2 << rhs2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -528,7 +547,7 @@ class Sentence
|
|||||||
}
|
}
|
||||||
changed = true
|
changed = true
|
||||||
while changed
|
while changed
|
||||||
changed = false
|
changed = false
|
||||||
channel_rules.each {|sym, set|
|
channel_rules.each {|sym, set|
|
||||||
n1 = set.size
|
n1 = set.size
|
||||||
set.keys.each {|s|
|
set.keys.each {|s|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user