One Rule object stores all alternative patterns
This commit is contained in:
parent
e4f2fffe50
commit
9cc1890ddc
@ -36,7 +36,7 @@ class Imbecile
|
|||||||
|
|
||||||
def initialize(input)
|
def initialize(input)
|
||||||
@tokens = []
|
@tokens = []
|
||||||
@rules = []
|
@rules = {}
|
||||||
input = input.gsub("\r\n", "\n")
|
input = input.gsub("\r\n", "\n")
|
||||||
while !input.empty?
|
while !input.empty?
|
||||||
parse_grammar(input)
|
parse_grammar(input)
|
||||||
@ -79,9 +79,10 @@ class Imbecile
|
|||||||
pattern = $1
|
pattern = $1
|
||||||
@tokens << Token.new(nil, pattern, @tokens.size)
|
@tokens << Token.new(nil, pattern, @tokens.size)
|
||||||
elsif input.slice!(/\A(\S+)\s*:\s*\[(.*?)\] <<\n(.*?)^>>\n/m)
|
elsif input.slice!(/\A(\S+)\s*:\s*\[(.*?)\] <<\n(.*?)^>>\n/m)
|
||||||
rule_name, rule, code = $1, $2, $3
|
rule_name, components, code = $1, $2, $3
|
||||||
rule = rule.strip.split(/\s+/)
|
components = components.strip.split(/\s+/)
|
||||||
@rules << Rule.new(rule_name, rule, code)
|
@rules[rule_name] ||= Rule.new(rule_name)
|
||||||
|
@rules[rule_name].add_pattern(components, code)
|
||||||
else
|
else
|
||||||
if input.size > 25
|
if input.size > 25
|
||||||
input = input.slice(0..20) + "..."
|
input = input.slice(0..20) + "..."
|
||||||
@ -97,24 +98,24 @@ class Imbecile
|
|||||||
end
|
end
|
||||||
token_names[token.name] = token
|
token_names[token.name] = token
|
||||||
end
|
end
|
||||||
rule_names = @rules.each_with_object({}) do |rule, rule_names|
|
@rules.each do |rule_name, rule|
|
||||||
if token_names.include?(rule.name)
|
if token_names.include?(rule_name)
|
||||||
raise Error.new("Rule name collides with token name #{rule.name}")
|
raise Error.new("Rule name collides with token name #{rule_name}")
|
||||||
end
|
end
|
||||||
rule_names[rule.name] ||= []
|
|
||||||
rule_names[rule.name] << rule
|
|
||||||
end
|
end
|
||||||
unless rule_names["Start"]
|
unless @rules["Start"]
|
||||||
raise Error.new("Start rule not found")
|
raise Error.new("Start rule not found")
|
||||||
end
|
end
|
||||||
@rules.each do |rule|
|
@rules.each do |rule_name, rule|
|
||||||
rule.components.map! do |component|
|
rule.patterns.each do |pattern|
|
||||||
if token_names[component]
|
pattern.components.map! do |component|
|
||||||
token_names[component]
|
if token_names[component]
|
||||||
elsif rule_names[component]
|
token_names[component]
|
||||||
rule_names[component]
|
elsif @rules[component]
|
||||||
else
|
@rules[component]
|
||||||
raise Error.new("Symbol #{component} not found")
|
else
|
||||||
|
raise Error.new("Symbol #{component} not found")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -3,9 +3,8 @@ class Imbecile
|
|||||||
class Parser
|
class Parser
|
||||||
|
|
||||||
def initialize(tokens, rules)
|
def initialize(tokens, rules)
|
||||||
start_rules = rules.select {|rule| rule.name == "Start"}
|
start_items = rules["Start"].patterns.map do |pattern|
|
||||||
start_items = start_rules.map do |rule|
|
Item.new(pattern, 0)
|
||||||
Item.new(rule, 0)
|
|
||||||
end
|
end
|
||||||
start_item_set = ItemSet.new(start_items)
|
start_item_set = ItemSet.new(start_items)
|
||||||
start_item_set.close!
|
start_item_set.close!
|
||||||
|
@ -3,24 +3,24 @@ class Imbecile
|
|||||||
|
|
||||||
class Item
|
class Item
|
||||||
|
|
||||||
attr_reader :rule
|
attr_reader :pattern
|
||||||
attr_reader :position
|
attr_reader :position
|
||||||
|
|
||||||
def initialize(rule, position)
|
def initialize(pattern, position)
|
||||||
@rule = rule
|
@pattern = pattern
|
||||||
@position = position
|
@position = position
|
||||||
end
|
end
|
||||||
|
|
||||||
def next_component
|
def next_component
|
||||||
@rule.components[@position]
|
@pattern.components[@position]
|
||||||
end
|
end
|
||||||
|
|
||||||
def hash
|
def hash
|
||||||
[@rule, @position].hash
|
[@pattern, @position].hash
|
||||||
end
|
end
|
||||||
|
|
||||||
def ==(other)
|
def ==(other)
|
||||||
@rule == other.rule && @position == other.position
|
@pattern == other.pattern && @position == other.position
|
||||||
end
|
end
|
||||||
|
|
||||||
def eql?(other)
|
def eql?(other)
|
||||||
@ -28,9 +28,9 @@ class Imbecile
|
|||||||
end
|
end
|
||||||
|
|
||||||
def closed_items
|
def closed_items
|
||||||
if @rule.components[@position].is_a?(Array)
|
if @pattern.components[@position].is_a?(Rule)
|
||||||
@rule.components[@position].map do |rule|
|
@pattern.components[@position].patterns.map do |pattern|
|
||||||
Item.new(rule, 0)
|
Item.new(pattern, 0)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
[]
|
[]
|
||||||
|
@ -2,16 +2,30 @@ class Imbecile
|
|||||||
|
|
||||||
class Rule
|
class Rule
|
||||||
|
|
||||||
|
class Pattern
|
||||||
|
|
||||||
|
attr_reader :components
|
||||||
|
|
||||||
|
attr_reader :code
|
||||||
|
|
||||||
|
def initialize(components, code)
|
||||||
|
@components = components
|
||||||
|
@code = code
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
attr_reader :name
|
attr_reader :name
|
||||||
|
|
||||||
attr_reader :components
|
attr_reader :patterns
|
||||||
|
|
||||||
attr_reader :code
|
def initialize(name)
|
||||||
|
|
||||||
def initialize(name, rule_components, code)
|
|
||||||
@name = name
|
@name = name
|
||||||
@components = rule_components
|
@patterns = []
|
||||||
@code = code
|
end
|
||||||
|
|
||||||
|
def add_pattern(components, code)
|
||||||
|
@patterns << Pattern.new(components, code)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user