# # irb/slex.rb - symple lex analizer # $Release Version: 0.9$ # $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, &block) # print node.inspect, "\n" if SLex.debug? postproc = block if block_given? node = create(token, preproc, postproc) end def def_rules(*tokens, &block) if block_given? p = block end for token in tokens def_rule(token, nil, p) end end def preproc(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 return 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("", @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 abstract 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 abstract 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