From 6ce94e15af7b0af6d049ba449c9ca2c3b5325e3d Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Sat, 28 Aug 2021 08:11:06 -0400 Subject: [PATCH] Expand rules --- lib/imbecile.rb | 78 +++++++++++++++++++++++++++--------------- lib/imbecile/parser.rb | 10 ++++++ 2 files changed, 61 insertions(+), 27 deletions(-) create mode 100644 lib/imbecile/parser.rb diff --git a/lib/imbecile.rb b/lib/imbecile.rb index c139d4b..bff56f8 100644 --- a/lib/imbecile.rb +++ b/lib/imbecile.rb @@ -7,6 +7,7 @@ require_relative "imbecile/fa/state" require_relative "imbecile/fa/state/transition" require_relative "imbecile/lexer" require_relative "imbecile/lexer/dfa" +require_relative "imbecile/parser" require_relative "imbecile/regex" require_relative "imbecile/regex/nfa" require_relative "imbecile/regex/unit" @@ -41,34 +42,9 @@ class Imbecile end def generate(output_file, log_file) - 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 + expand_rules lexer = Lexer.new(@tokens) + parser = Parser.new(@tokens, @rules) 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, "<>") result = erb.result(binding.clone) @@ -112,6 +88,54 @@ class Imbecile 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 def run(input_file, output_file, log_file) diff --git a/lib/imbecile/parser.rb b/lib/imbecile/parser.rb new file mode 100644 index 0000000..023b00a --- /dev/null +++ b/lib/imbecile/parser.rb @@ -0,0 +1,10 @@ +class Imbecile + + class Parser + + def initialize(tokens, rules) + end + + end + +end