うーん、果たして他の言語に応用できるもんか…
%%{ machine ruby_machine; action Y { yield(data, head, fpc); head = fpc + 1; } main := ( (lower+ ' ') @Y )* ; }%% class RubyMachine %% write data; def self.parse(data) head = 0 %% write init; %% write exec; end end RubyMachine.parse("abcd efg hijk ") do |data, head, fpc| p data.slice(head..fpc) end
value分かりずらい。まんま部分文字列取れたらいいのに。
出力はこんな感じ。
"abcd "
"efg "
"hijk "
Rubyファイルがこんな感じ。まあ、読めないです。
# line 1 "ruby_machine.rl" # line 5 "ruby_machine.rl" class RubyMachine # line 8 "ruby_machine.rb" class << self attr_accessor :_ruby_machine_actions private :_ruby_machine_actions, :_ruby_machine_actions= end self._ruby_machine_actions = [ 0, 1, 0 ] class << self attr_accessor :_ruby_machine_key_offsets private :_ruby_machine_key_offsets, :_ruby_machine_key_offsets= end self._ruby_machine_key_offsets = [ 0, 0, 3 ] class << self attr_accessor :_ruby_machine_trans_keys private :_ruby_machine_trans_keys, :_ruby_machine_trans_keys= end self._ruby_machine_trans_keys = [ 32, 97, 122, 97, 122, 0 ] class << self attr_accessor :_ruby_machine_single_lengths private :_ruby_machine_single_lengths, :_ruby_machine_single_lengths= end self._ruby_machine_single_lengths = [ 0, 1, 0 ] class << self attr_accessor :_ruby_machine_range_lengths private :_ruby_machine_range_lengths, :_ruby_machine_range_lengths= end self._ruby_machine_range_lengths = [ 0, 1, 1 ] class << self attr_accessor :_ruby_machine_index_offsets private :_ruby_machine_index_offsets, :_ruby_machine_index_offsets= end self._ruby_machine_index_offsets = [ 0, 0, 3 ] class << self attr_accessor :_ruby_machine_trans_targs_wi private :_ruby_machine_trans_targs_wi, :_ruby_machine_trans_targs_wi= end self._ruby_machine_trans_targs_wi = [ 2, 1, 0, 1, 0, 0 ] class << self attr_accessor :_ruby_machine_trans_actions_wi private :_ruby_machine_trans_actions_wi, :_ruby_machine_trans_actions_wi= end self._ruby_machine_trans_actions_wi = [ 1, 0, 0, 0, 0, 0 ] class << self attr_accessor :ruby_machine_start end self.ruby_machine_start = 2; class << self attr_accessor :ruby_machine_first_final end self.ruby_machine_first_final = 2; class << self attr_accessor :ruby_machine_error end self.ruby_machine_error = 0; class << self attr_accessor :ruby_machine_en_main end self.ruby_machine_en_main = 2; # line 9 "ruby_machine.rl" def self.parse(data) head = 0 # line 96 "ruby_machine.rb" begin p ||= 0 pe ||= data.length cs = ruby_machine_start end # line 13 "ruby_machine.rl" # line 104 "ruby_machine.rb" begin _klen, _trans, _keys, _acts, _nacts = nil _goto_level = 0 _resume = 10 _eof_trans = 15 _again = 20 _test_eof = 30 _out = 40 while true _trigger_goto = false if _goto_level <= 0 if p == pe _goto_level = _test_eof next end if cs == 0 _goto_level = _out next end end if _goto_level <= _resume _keys = _ruby_machine_key_offsets[cs] _trans = _ruby_machine_index_offsets[cs] _klen = _ruby_machine_single_lengths[cs] _break_match = false begin if _klen > 0 _lower = _keys _upper = _keys + _klen - 1 loop do break if _upper < _lower _mid = _lower + ( (_upper - _lower) >> 1 ) if data[p] < _ruby_machine_trans_keys[_mid] _upper = _mid - 1 elsif data[p] > _ruby_machine_trans_keys[_mid] _lower = _mid + 1 else _trans += (_mid - _keys) _break_match = true break end end # loop break if _break_match _keys += _klen _trans += _klen end _klen = _ruby_machine_range_lengths[cs] if _klen > 0 _lower = _keys _upper = _keys + (_klen << 1) - 2 loop do break if _upper < _lower _mid = _lower + (((_upper-_lower) >> 1) & ~1) if data[p] < _ruby_machine_trans_keys[_mid] _upper = _mid - 2 elsif data[p] > _ruby_machine_trans_keys[_mid+1] _lower = _mid + 2 else _trans += ((_mid - _keys) >> 1) _break_match = true break end end # loop break if _break_match _trans += _klen end end while false cs = _ruby_machine_trans_targs_wi[_trans] if _ruby_machine_trans_actions_wi[_trans] != 0 _acts = _ruby_machine_trans_actions_wi[_trans] _nacts = _ruby_machine_actions[_acts] _acts += 1 while _nacts > 0 _nacts -= 1 _acts += 1 case _ruby_machine_actions[_acts - 1] when 0 then # line 3 "ruby_machine.rl" begin yield(data, head, p); head = p + 1; end # line 3 "ruby_machine.rl" # line 189 "ruby_machine.rb" end # action switch end end if _trigger_goto next end end if _goto_level <= _again if cs == 0 _goto_level = _out next end p += 1 if p != pe _goto_level = _resume next end end if _goto_level <= _test_eof end if _goto_level <= _out break end end end # line 14 "ruby_machine.rl" end end RubyMachine.parse("abcd efg hijk ") do |data, head, fpc| p data.slice(head..fpc) end