ruby/lib/irb/slex.rb

280 строки
5.6 KiB
Ruby
Исходник Обычный вид История

#
# irb/slex.rb - symple lex analizer
# $Release Version: 0.7.3$
# $Revision$
# $Date$
# by Keiju ISHITSUKA(keiju@ishituska.com)
#
# --
#
#
#
require "e2mmap"
class SLex
@RCS_ID='-$Id$-'
extend Exception2MessageMapper
def_exception :ErrNodeNothing, "node nothing"
def_exception :ErrNodeAlreadyExists, "node already exists"
class << self
attr_accessor :debug_level
def debug?
debug_level > 0
end
end
@debug_level = 0
def initialize
@head = Node.new("")
end
def def_rule(token, preproc = nil, postproc = nil)
# print node.inspect, "\n" if SLex.debug?
postproc = proc if iterator?
node = create(token, preproc, postproc)
end
def def_rules(*tokens)
if iterator?
p = proc
end
for token in tokens
def_rule(token, nil, p)
end
end
def preporc(token, proc)
node = search(token)
node.preproc=proc
end
def postproc(token)
node = search(token, proc)
node.postproc=proc
end
def search(token)
@head.search(token.split(//))
end
def create(token, preproc = nil, postproc = nil)
@head.create_subnode(token.split(//), preproc, postproc)
end
def match(token)
case token
when Array
when String
token = token.split(//)
match(token.split(//))
else
return @head.match_io(token)
end
ret = @head.match(token)
printf "match end: %s:%s", ret, token.inspect if SLex.debug?
ret
end
def inspect
format("<SLex: @head = %s>", @head.inspect)
end
#----------------------------------------------------------------------
#
# class Node -
#
#----------------------------------------------------------------------
class Node
# if postproc is nil, this node is an abstract node.
# if postproc is non-nil, this node is a real node.
def initialize(preproc = nil, postproc = nil)
@Tree = {}
@preproc = preproc
@postproc = postproc
end
attr_accessor :preproc
attr_accessor :postproc
def search(chrs, opt = nil)
return self if chrs.empty?
ch = chrs.shift
if node = @Tree[ch]
node.search(chrs, opt)
else
if opt
chrs.unshift ch
self.create_subnode(chrs)
else
SLex.fail ErrNodeNothing
end
end
end
def create_subnode(chrs, preproc = nil, postproc = nil)
if chrs.empty?
if @postproc
p node
SLex.fail ErrNodeAlreadyExists
else
print "Warn: change abstruct node to real node\n" if SLex.debug?
@preproc = preproc
@postproc = postproc
end
return self
end
ch = chrs.shift
if node = @Tree[ch]
if chrs.empty?
if node.postproc
p node
p self
p ch
p chrs
SLex.fail ErrNodeAlreadyExists
else
print "Warn: change abstruct node to real node\n" if SLex.debug?
node.preproc = preproc
node.postproc = postproc
end
else
node.create_subnode(chrs, preproc, postproc)
end
else
if chrs.empty?
node = Node.new(preproc, postproc)
else
node = Node.new
node.create_subnode(chrs, preproc, postproc)
end
@Tree[ch] = node
end
node
end
#
# chrs: String
# character array
# io must have getc()/ungetc(); and ungetc() must be
# able to be called arbitrary number of times.
#
def match(chrs, op = "")
print "match>: ", chrs, "op:", op, "\n" if SLex.debug?
if chrs.empty?
if @preproc.nil? || @preproc.call(op, chrs)
printf "op1: %s\n", op if SLex.debug?
@postproc.call(op, chrs)
else
nil
end
else
ch = chrs.shift
if node = @Tree[ch]
if ret = node.match(chrs, op+ch)
return ret
else
chrs.unshift ch
if @postproc and @preproc.nil? || @preproc.call(op, chrs)
printf "op2: %s\n", op.inspect if SLex.debug?
ret = @postproc.call(op, chrs)
return ret
else
return nil
end
end
else
chrs.unshift ch
if @postproc and @preproc.nil? || @preproc.call(op, chrs)
printf "op3: %s\n", op if SLex.debug?
@postproc.call(op, chrs)
return ""
else
return nil
end
end
end
end
def match_io(io, op = "")
if op == ""
ch = io.getc
if ch == nil
return nil
end
else
ch = io.getc_of_rests
end
if ch.nil?
if @preproc.nil? || @preproc.call(op, io)
printf "op1: %s\n", op if SLex.debug?
@postproc.call(op, io)
else
nil
end
else
if node = @Tree[ch]
if ret = node.match_io(io, op+ch)
ret
else
io.ungetc ch
if @postproc and @preproc.nil? || @preproc.call(op, io)
printf "op2: %s\n", op.inspect if SLex.debug?
@postproc.call(op, io)
else
nil
end
end
else
io.ungetc ch
if @postproc and @preproc.nil? || @preproc.call(op, io)
printf "op3: %s\n", op if SLex.debug?
@postproc.call(op, io)
else
nil
end
end
end
end
end
end
if $0 == __FILE__
# Tracer.on
case $1
when "1"
tr = SLex.new
print "0: ", tr.inspect, "\n"
tr.def_rule("=") {print "=\n"}
print "1: ", tr.inspect, "\n"
tr.def_rule("==") {print "==\n"}
print "2: ", tr.inspect, "\n"
print "case 1:\n"
print tr.match("="), "\n"
print "case 2:\n"
print tr.match("=="), "\n"
print "case 3:\n"
print tr.match("=>"), "\n"
when "2"
tr = SLex.new
print "0: ", tr.inspect, "\n"
tr.def_rule("=") {print "=\n"}
print "1: ", tr.inspect, "\n"
tr.def_rule("==", proc{false}) {print "==\n"}
print "2: ", tr.inspect, "\n"
print "case 1:\n"
print tr.match("="), "\n"
print "case 2:\n"
print tr.match("=="), "\n"
print "case 3:\n"
print tr.match("=>"), "\n"
end
exit
end