Move FA class out of Regex class
This commit is contained in:
parent
37d6917b49
commit
28591907c1
@ -2,17 +2,17 @@ require "erb"
|
||||
require "set"
|
||||
require_relative "imbecile/cli"
|
||||
require_relative "imbecile/code_point_range"
|
||||
require_relative "imbecile/fa"
|
||||
require_relative "imbecile/fa/state"
|
||||
require_relative "imbecile/fa/state/transition"
|
||||
require_relative "imbecile/generator"
|
||||
require_relative "imbecile/grammar"
|
||||
require_relative "imbecile/grammar/rule"
|
||||
require_relative "imbecile/grammar/token"
|
||||
require_relative "imbecile/lexer_dfa"
|
||||
require_relative "imbecile/regex"
|
||||
require_relative "imbecile/regex/fa"
|
||||
require_relative "imbecile/regex/fa/state"
|
||||
require_relative "imbecile/regex/fa/state/transition"
|
||||
require_relative "imbecile/regex/nfa"
|
||||
require_relative "imbecile/regex/unit"
|
||||
require_relative "imbecile/lexer_dfa"
|
||||
require_relative "imbecile/version"
|
||||
|
||||
module Imbecile
|
||||
|
90
lib/imbecile/fa.rb
Normal file
90
lib/imbecile/fa.rb
Normal file
@ -0,0 +1,90 @@
|
||||
module Imbecile
|
||||
|
||||
class FA
|
||||
|
||||
attr_reader :start_state
|
||||
|
||||
def initialize
|
||||
@start_state = State.new
|
||||
end
|
||||
|
||||
def to_s
|
||||
chr = lambda do |value|
|
||||
if value < 32 || value > 127
|
||||
"{#{value}}"
|
||||
else
|
||||
value.chr
|
||||
end
|
||||
end
|
||||
rv = ""
|
||||
states = enumerate
|
||||
states.each do |state, id|
|
||||
accepts_s = state.accepts ? " #{state.accepts}" : ""
|
||||
rv += "#{id}#{accepts_s}:\n"
|
||||
state.transitions.each do |transition|
|
||||
if transition.nil?
|
||||
range_s = "nil"
|
||||
else
|
||||
range_s = chr[transition.code_point_range.first]
|
||||
if transition.code_point_range.size > 1
|
||||
range_s += "-" + chr[transition.code_point_range.last]
|
||||
end
|
||||
end
|
||||
accepts_s = transition.destination.accepts ? " #{transition.destination.accepts}" : ""
|
||||
rv += " #{range_s} => #{states[transition.destination]}#{accepts_s}\n"
|
||||
end
|
||||
end
|
||||
rv
|
||||
end
|
||||
|
||||
def enumerate
|
||||
@_enumerated ||=
|
||||
begin
|
||||
id = 0
|
||||
states = {}
|
||||
visit = lambda do |state|
|
||||
unless states.include?(state)
|
||||
states[state] = id
|
||||
id += 1
|
||||
state.transitions.each do |transition|
|
||||
visit[transition.destination]
|
||||
end
|
||||
end
|
||||
end
|
||||
visit[@start_state]
|
||||
states
|
||||
end
|
||||
end
|
||||
|
||||
def build_tables
|
||||
transition_table = []
|
||||
state_table = []
|
||||
states = enumerate
|
||||
states.each do |state, id|
|
||||
accepts =
|
||||
if state.accepts.nil?
|
||||
TOKEN_NONE
|
||||
elsif state.accepts.name
|
||||
state.accepts.id
|
||||
else
|
||||
TOKEN_DROP
|
||||
end
|
||||
state_table << {
|
||||
transition_table_index: transition_table.size,
|
||||
n_transitions: state.transitions.size,
|
||||
accepts: accepts,
|
||||
}
|
||||
state.transitions.each do |transition|
|
||||
transition_table << {
|
||||
first: transition.code_point_range.first,
|
||||
last: transition.code_point_range.last,
|
||||
destination: states[transition.destination],
|
||||
}
|
||||
end
|
||||
end
|
||||
[transition_table, state_table]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
51
lib/imbecile/fa/state.rb
Normal file
51
lib/imbecile/fa/state.rb
Normal file
@ -0,0 +1,51 @@
|
||||
module Imbecile
|
||||
class FA
|
||||
|
||||
class State
|
||||
|
||||
attr_accessor :accepts
|
||||
attr_reader :transitions
|
||||
|
||||
def initialize
|
||||
@transitions = []
|
||||
end
|
||||
|
||||
def add_transition(code_point_range, destination)
|
||||
@transitions << Transition.new(code_point_range, destination)
|
||||
end
|
||||
|
||||
# Determine the set of states that can be reached by nil transitions.
|
||||
# from this state.
|
||||
#
|
||||
# @return [Set<NFA::State>]
|
||||
# Set of states.
|
||||
def nil_transition_states
|
||||
states = Set[self]
|
||||
analyze_state = lambda do |state|
|
||||
state.nil_transitions.each do |transition|
|
||||
unless states.include?(transition.destination)
|
||||
states << transition.destination
|
||||
analyze_state[transition.destination]
|
||||
end
|
||||
end
|
||||
end
|
||||
analyze_state[self]
|
||||
states
|
||||
end
|
||||
|
||||
def nil_transitions
|
||||
@transitions.select do |transition|
|
||||
transition.nil?
|
||||
end
|
||||
end
|
||||
|
||||
def cp_transitions
|
||||
@transitions.reject do |transition|
|
||||
transition.nil?
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
23
lib/imbecile/fa/state/transition.rb
Normal file
23
lib/imbecile/fa/state/transition.rb
Normal file
@ -0,0 +1,23 @@
|
||||
module Imbecile
|
||||
class FA
|
||||
class State
|
||||
|
||||
class Transition
|
||||
|
||||
attr_reader :code_point_range
|
||||
attr_reader :destination
|
||||
|
||||
def initialize(code_point_range, destination)
|
||||
@code_point_range = code_point_range
|
||||
@destination = destination
|
||||
end
|
||||
|
||||
def nil?
|
||||
@code_point_range.nil?
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
@ -1,6 +1,6 @@
|
||||
module Imbecile
|
||||
|
||||
class LexerDFA < Regex::FA
|
||||
class LexerDFA < FA
|
||||
|
||||
def initialize(tokens)
|
||||
super()
|
||||
|
@ -1,92 +0,0 @@
|
||||
module Imbecile
|
||||
class Regex
|
||||
|
||||
class FA
|
||||
|
||||
attr_reader :start_state
|
||||
|
||||
def initialize
|
||||
@start_state = State.new
|
||||
end
|
||||
|
||||
def to_s
|
||||
chr = lambda do |value|
|
||||
if value < 32 || value > 127
|
||||
"{#{value}}"
|
||||
else
|
||||
value.chr
|
||||
end
|
||||
end
|
||||
rv = ""
|
||||
states = enumerate
|
||||
states.each do |state, id|
|
||||
accepts_s = state.accepts ? " #{state.accepts}" : ""
|
||||
rv += "#{id}#{accepts_s}:\n"
|
||||
state.transitions.each do |transition|
|
||||
if transition.nil?
|
||||
range_s = "nil"
|
||||
else
|
||||
range_s = chr[transition.code_point_range.first]
|
||||
if transition.code_point_range.size > 1
|
||||
range_s += "-" + chr[transition.code_point_range.last]
|
||||
end
|
||||
end
|
||||
accepts_s = transition.destination.accepts ? " #{transition.destination.accepts}" : ""
|
||||
rv += " #{range_s} => #{states[transition.destination]}#{accepts_s}\n"
|
||||
end
|
||||
end
|
||||
rv
|
||||
end
|
||||
|
||||
def enumerate
|
||||
@_enumerated ||=
|
||||
begin
|
||||
id = 0
|
||||
states = {}
|
||||
visit = lambda do |state|
|
||||
unless states.include?(state)
|
||||
states[state] = id
|
||||
id += 1
|
||||
state.transitions.each do |transition|
|
||||
visit[transition.destination]
|
||||
end
|
||||
end
|
||||
end
|
||||
visit[@start_state]
|
||||
states
|
||||
end
|
||||
end
|
||||
|
||||
def build_tables
|
||||
transition_table = []
|
||||
state_table = []
|
||||
states = enumerate
|
||||
states.each do |state, id|
|
||||
accepts =
|
||||
if state.accepts.nil?
|
||||
TOKEN_NONE
|
||||
elsif state.accepts.name
|
||||
state.accepts.id
|
||||
else
|
||||
TOKEN_DROP
|
||||
end
|
||||
state_table << {
|
||||
transition_table_index: transition_table.size,
|
||||
n_transitions: state.transitions.size,
|
||||
accepts: accepts,
|
||||
}
|
||||
state.transitions.each do |transition|
|
||||
transition_table << {
|
||||
first: transition.code_point_range.first,
|
||||
last: transition.code_point_range.last,
|
||||
destination: states[transition.destination],
|
||||
}
|
||||
end
|
||||
end
|
||||
[transition_table, state_table]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -1,53 +0,0 @@
|
||||
module Imbecile
|
||||
class Regex
|
||||
class FA
|
||||
|
||||
class State
|
||||
|
||||
attr_accessor :accepts
|
||||
attr_reader :transitions
|
||||
|
||||
def initialize
|
||||
@transitions = []
|
||||
end
|
||||
|
||||
def add_transition(code_point_range, destination)
|
||||
@transitions << Transition.new(code_point_range, destination)
|
||||
end
|
||||
|
||||
# Determine the set of states that can be reached by nil transitions.
|
||||
# from this state.
|
||||
#
|
||||
# @return [Set<NFA::State>]
|
||||
# Set of states.
|
||||
def nil_transition_states
|
||||
states = Set[self]
|
||||
analyze_state = lambda do |state|
|
||||
state.nil_transitions.each do |transition|
|
||||
unless states.include?(transition.destination)
|
||||
states << transition.destination
|
||||
analyze_state[transition.destination]
|
||||
end
|
||||
end
|
||||
end
|
||||
analyze_state[self]
|
||||
states
|
||||
end
|
||||
|
||||
def nil_transitions
|
||||
@transitions.select do |transition|
|
||||
transition.nil?
|
||||
end
|
||||
end
|
||||
|
||||
def cp_transitions
|
||||
@transitions.reject do |transition|
|
||||
transition.nil?
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
@ -1,25 +0,0 @@
|
||||
module Imbecile
|
||||
class Regex
|
||||
class FA
|
||||
class State
|
||||
|
||||
class Transition
|
||||
|
||||
attr_reader :code_point_range
|
||||
attr_reader :destination
|
||||
|
||||
def initialize(code_point_range, destination)
|
||||
@code_point_range = code_point_range
|
||||
@destination = destination
|
||||
end
|
||||
|
||||
def nil?
|
||||
@code_point_range.nil?
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
x
Reference in New Issue
Block a user