Expand rules

This commit is contained in:
Josh Holtrop 2021-08-28 08:11:06 -04:00
parent 3f92ae46c4
commit 6ce94e15af
2 changed files with 61 additions and 27 deletions

View File

@ -7,6 +7,7 @@ require_relative "imbecile/fa/state"
require_relative "imbecile/fa/state/transition" require_relative "imbecile/fa/state/transition"
require_relative "imbecile/lexer" require_relative "imbecile/lexer"
require_relative "imbecile/lexer/dfa" require_relative "imbecile/lexer/dfa"
require_relative "imbecile/parser"
require_relative "imbecile/regex" require_relative "imbecile/regex"
require_relative "imbecile/regex/nfa" require_relative "imbecile/regex/nfa"
require_relative "imbecile/regex/unit" require_relative "imbecile/regex/unit"
@ -41,34 +42,9 @@ class Imbecile
end end
def generate(output_file, log_file) def generate(output_file, log_file)
token_names = @tokens.each_with_object({}) do |token, token_names| expand_rules
if token_names.include?(token.name)
raise Error.new("Duplicate token name #{token.name}")
end
token_names[token.name] = token
end
rule_names = @rules.each_with_object({}) do |rule, rule_names|
if token_names.include?(rule.name)
raise Error.new("Rule name collides with token name #{rule.name}")
end
rule_names[rule.name] ||= []
rule_names[rule.name] << rule
end
unless rule_names["Start"]
raise Error.new("Start rule not found")
end
@rules.each do |rule|
rule.components.map! do |component|
if token_names[component]
token_names[component]
elsif rule_names[component]
rule_names[component]
else
raise Error.new("Symbol #{component} not found")
end
end
end
lexer = Lexer.new(@tokens) lexer = Lexer.new(@tokens)
parser = Parser.new(@tokens, @rules)
classname = @classname || File.basename(output_file).sub(%r{[^a-zA-Z0-9].*}, "").capitalize classname = @classname || File.basename(output_file).sub(%r{[^a-zA-Z0-9].*}, "").capitalize
erb = ERB.new(File.read(File.join(File.dirname(File.expand_path(__FILE__)), "../assets/parser.d.erb")), nil, "<>") erb = ERB.new(File.read(File.join(File.dirname(File.expand_path(__FILE__)), "../assets/parser.d.erb")), nil, "<>")
result = erb.result(binding.clone) result = erb.result(binding.clone)
@ -112,6 +88,54 @@ class Imbecile
end end
end end
def expand_rules
token_names = @tokens.each_with_object({}) do |token, token_names|
if token_names.include?(token.name)
raise Error.new("Duplicate token name #{token.name}")
end
token_names[token.name] = token
end
rule_names = @rules.each_with_object({}) do |rule, rule_names|
if token_names.include?(rule.name)
raise Error.new("Rule name collides with token name #{rule.name}")
end
rule_names[rule.name] ||= []
rule_names[rule.name] << rule
end
unless rule_names["Start"]
raise Error.new("Start rule not found")
end
@rules.each do |rule|
rule.components.map! do |component|
if token_names[component]
token_names[component]
elsif rule_names[component]
rule_names[component]
else
raise Error.new("Symbol #{component} not found")
end
end
end
new_rules = []
begin
@rules += new_rules
new_rules = []
@rules.delete_if do |rule|
replaced = false
rule.components.each_with_index do |component, index|
if component.is_a?(Array)
component.each do |new_component|
new_components = rule.components[0, index] + [new_component] + rule.components[index + 1, rule.components.size]
new_rules << Rule.new(rule.name, new_components, rule.code)
end
replaced = true
end
end
replaced
end
end while new_rules.size > 0
end
class << self class << self
def run(input_file, output_file, log_file) def run(input_file, output_file, log_file)

10
lib/imbecile/parser.rb Normal file
View File

@ -0,0 +1,10 @@
class Imbecile
class Parser
def initialize(tokens, rules)
end
end
end