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 "set"
|
||||||
require_relative "imbecile/cli"
|
require_relative "imbecile/cli"
|
||||||
require_relative "imbecile/code_point_range"
|
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/generator"
|
||||||
require_relative "imbecile/grammar"
|
require_relative "imbecile/grammar"
|
||||||
require_relative "imbecile/grammar/rule"
|
require_relative "imbecile/grammar/rule"
|
||||||
require_relative "imbecile/grammar/token"
|
require_relative "imbecile/grammar/token"
|
||||||
|
require_relative "imbecile/lexer_dfa"
|
||||||
require_relative "imbecile/regex"
|
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/nfa"
|
||||||
require_relative "imbecile/regex/unit"
|
require_relative "imbecile/regex/unit"
|
||||||
require_relative "imbecile/lexer_dfa"
|
|
||||||
require_relative "imbecile/version"
|
require_relative "imbecile/version"
|
||||||
|
|
||||||
module Imbecile
|
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
|
module Imbecile
|
||||||
|
|
||||||
class LexerDFA < Regex::FA
|
class LexerDFA < FA
|
||||||
|
|
||||||
def initialize(tokens)
|
def initialize(tokens)
|
||||||
super()
|
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