SQL & Regex(3): subset construction

来源:互联网 发布:网络教育哪个大学好 编辑:程序博客网 时间:2024/06/05 07:21


-- Subset Construction: convert NFA to DFA
-- require: NFA_trans_table is filled with NFA state data
-- ========================================================================
exec clearobj 'DFA_states', 1
go
create table DFA_states(state nvarchar(100), code char, marked bit)
go
-- ========================================================================
exec clearobj 'DFA_final_state_set', 1
go
create table DFA_final_state_set(state nvarchar(100))
go
-- ========================================================================
exec clearobj 'DFA_trans_table', 1
go

create table DFA_trans_table(from_state nvarchar(100), to_state nvarchar(100), input char default '')
--     ,constraint PK_DFA primary key(from_state, to_state))
go
-- ========================================================================
exec clearobj 'NFA_eps_closure', 1
go
create function NFA_eps_closure(@NFA_state_set nvarchar(100))
    returns nvarchar(100)
with encryption
as
begin
    declare @result_state_set nvarchar(100), @curr_state int, @EPSILON char
    select @EPSILON = '#', @result_state_set = ''
    declare @tb table(state int, marked bit)
    insert @tb select
        substring(@NFA_state_set,
            charindex(',', ','+@NFA_state_set, seqno),
            charindex(',', @NFA_state_set+',', seqno) - charindex(',', ','+@NFA_state_set, seqno)),
        0
    from seq where seqno <= len(@NFA_state_set) and substring(','+@NFA_state_set, seqno, 1) = ','

    while exists(select * from @tb where marked = 0)
    begin
        select top 1 @curr_state = state from @tb where marked = 0
        update @tb set marked = 1 where state = @curr_state

        insert @tb select to_state, 0 from NFA_trans_table where from_state = @curr_state and input = @EPSILON
            and to_state not in (select state from @tb)
    end

    select @result_state_set = @result_state_set + ltrim(str(state)) + ',' from @tb order by state
    return case when @result_state_set <> '' then left(@result_state_set, len(@result_state_set) - 1) else '' end
end
go
-- ========================================================================
exec clearobj 'NFA_move', 1
go

create function NFA_move(@NFA_state_set nvarchar(100), @input char)
    returns nvarchar(100)
with encryption
as
begin
    declare @result_state_set nvarchar(100), @curr_state int, @EPSILON char
    select @EPSILON = '#', @result_state_set = ''
    declare @tb table(state int)
    insert @tb select to_state from NFA_trans_table where input = @input and charindex(ltrim(str(from_state)), @NFA_state_set) > 0
    if not exists(select * from @tb)
        return ''

    select @result_state_set = @result_state_set + ltrim(str(state)) + ',' from @tb order by state
    return left(@result_state_set, len(@result_state_set) - 1)
end
go
-- ========================================================================
exec clearobj 'subset_construction', 1
go

create proc subset_construction
with encryption
as
delete from DFA_states
delete from DFA_final_state_set
delete from DFA_trans_table

declare @NFA_initial int, @NFA_finish int
declare @all_NFA_input nvarchar(100), @EPSILON char, @i int
declare @a_state nvarchar(100), @next nvarchar(100), @current_code char

select @NFA_initial=initial, @NFA_finish=final from NFA_property where nid = (select [id] from parse_node where isnull(pid, 0) = 0)
select @all_NFA_input = '', @EPSILON = '#', @i = 0, @current_code = 'A'
select @all_NFA_input = @all_NFA_input + input from NFA_trans_table where input <> @EPSILON group by input

insert DFA_states select dbo.NFA_eps_closure(ltrim(str(@NFA_initial))), @current_code, 0
set @current_code = char(unicode(@current_code) + 1)

while exists(select * from DFA_states where marked = 0)
begin
    select top 1 @a_state = state from DFA_states where marked = 0
    update DFA_states set marked = 1 where state = @a_state

    select @i = 1
    while @i <= len(@all_NFA_input)
    begin
        set @next = dbo.NFA_eps_closure(dbo.NFA_move(@a_state, substring(@all_NFA_input, @i, 1)))
         if @next not in (select state from DFA_states)
        begin
            if charindex(ltrim(str(@NFA_finish)), @next) > 0 insert DFA_final_state_set select @next
             insert DFA_states select @next, @current_code, 0
            set @current_code = char(unicode(@current_code) + 1)
        end
        insert DFA_trans_table select @a_state, @next, substring(@all_NFA_input, @i, 1)

        select @i = @i + 1
    end

    --delete entry which from_state is dead state
    delete from DFA_trans_table where from_state = ''
end
go
-- ========================================================================
exec clearobj 'NFA_print', 1
go
create proc NFA_print
with encryption
as
declare @i int, @j int, @size int, @str nvarchar(4000), @DELIMITER char, @NONE char
select @DELIMITER = '', @NONE = '_'
set @size = (select max(from_state) from NFA_trans_table)
select @i = 0, @str = '>>' + @DELIMITER

print 'NFA matrix:'
print replicate('-', 6 * @size)
while @i <= @size select @str = @str + right('0' + ltrim(str(@i)), 2) + @DELIMITER, @i = @i + 1
print @str
print replicate('-', 6 * @size)

select @i = 0
while @i <= @size
begin
    select @j = 0, @str =  right('0' + ltrim(str(@i)), 2)
    while @j <= @size
        select @str = @str + @DELIMITER + @NONE + isnull((select input from NFA_trans_table where from_state = @i and to_state = @j), @NONE), @j = @j + 1
    print @str
    select @str = ''
    select @i = @i + 1
end
print ''
go
-- ================================================================
exec subset_construction
select * from DFA_trans_table