lib/irb/slex.rb


DEFINITIONS

This source file includes following functions.


   1  #
   2  #   irb/slex.rb - symple lex analizer
   3  #       $Release Version: 0.9$
   4  #       $Revision: 1.4 $
   5  #       $Date: 2002/07/09 11:17:16 $
   6  #       by Keiju ISHITSUKA(keiju@ishituska.com)
   7  #
   8  # --
   9  #
  10  #   
  11  #
  12  
  13  require "e2mmap"
  14  
  15  class SLex
  16    @RCS_ID='-$Id: slex.rb,v 1.4 2002/07/09 11:17:16 keiju Exp $-'
  17  
  18    extend Exception2MessageMapper
  19    def_exception :ErrNodeNothing, "node nothing"
  20    def_exception :ErrNodeAlreadyExists, "node already exists"
  21  
  22    class << self
  23      attr_accessor :debug_level
  24      def debug?
  25        debug_level > 0
  26      end
  27    end
  28    @debug_level = 0
  29  
  30    def initialize
  31      @head = Node.new("")
  32    end
  33    
  34    def def_rule(token, preproc = nil, postproc = nil)
  35      #      print node.inspect, "\n" if SLex.debug?
  36      postproc = proc if iterator?
  37      node = create(token, preproc, postproc)
  38    end
  39    
  40    def def_rules(*tokens)
  41      if iterator?
  42        p = proc
  43      end
  44      for token in tokens
  45        def_rule(token, nil, p)
  46      end
  47    end
  48    
  49    def preporc(token, proc)
  50      node = search(token)
  51      node.preproc=proc
  52    end
  53    
  54    def postproc(token)
  55      node = search(token, proc)
  56      node.postproc=proc
  57    end
  58    
  59    def search(token)
  60      @head.search(token.split(//))
  61    end
  62  
  63    def create(token, preproc = nil, postproc = nil)
  64      @head.create_subnode(token.split(//), preproc, postproc)
  65    end
  66    
  67    def match(token)
  68      case token
  69      when Array
  70      when String
  71        return match(token.split(//))
  72      else
  73        return @head.match_io(token)
  74      end
  75      ret = @head.match(token)
  76      printf "match end: %s:%s", ret, token.inspect if SLex.debug?
  77      ret
  78    end
  79    
  80    def inspect
  81      format("<SLex: @head = %s>", @head.inspect)
  82    end
  83  
  84    #----------------------------------------------------------------------
  85    #
  86    #   class Node - 
  87    #
  88    #----------------------------------------------------------------------
  89    class Node
  90      # if postproc is nil, this node is an abstract node.
  91      # if postproc is non-nil, this node is a real node.
  92      def initialize(preproc = nil, postproc = nil)
  93        @Tree = {}
  94        @preproc = preproc
  95        @postproc = postproc
  96      end
  97  
  98      attr_accessor :preproc
  99      attr_accessor :postproc
 100      
 101      def search(chrs, opt = nil)
 102        return self if chrs.empty?
 103        ch = chrs.shift
 104        if node = @Tree[ch]
 105          node.search(chrs, opt)
 106        else
 107          if opt
 108            chrs.unshift ch
 109            self.create_subnode(chrs)
 110          else
 111            SLex.fail ErrNodeNothing
 112          end
 113        end
 114      end
 115      
 116      def create_subnode(chrs, preproc = nil, postproc = nil)
 117        if chrs.empty?
 118          if @postproc
 119            p node
 120            SLex.fail ErrNodeAlreadyExists
 121          else
 122            print "Warn: change abstruct node to real node\n" if SLex.debug?
 123            @preproc = preproc
 124            @postproc = postproc
 125          end
 126          return self
 127        end
 128        
 129        ch = chrs.shift
 130        if node = @Tree[ch]
 131          if chrs.empty?
 132            if node.postproc
 133              p node
 134              p self
 135              p ch
 136              p chrs
 137              SLex.fail ErrNodeAlreadyExists
 138            else
 139              print "Warn: change abstruct node to real node\n" if SLex.debug?
 140              node.preproc = preproc
 141              node.postproc = postproc
 142            end
 143          else
 144            node.create_subnode(chrs, preproc, postproc)
 145          end
 146        else
 147          if chrs.empty?
 148            node = Node.new(preproc, postproc)
 149          else
 150            node = Node.new
 151            node.create_subnode(chrs, preproc, postproc)
 152          end
 153          @Tree[ch] = node
 154        end
 155        node
 156      end
 157  
 158      #
 159      # chrs: String
 160      #       character array
 161      #       io must have getc()/ungetc(); and ungetc() must be
 162      #       able to be called arbitrary number of times. 
 163      #
 164      def match(chrs, op = "")
 165        print "match>: ", chrs, "op:", op, "\n" if SLex.debug?
 166        if chrs.empty?
 167          if @preproc.nil? || @preproc.call(op, chrs)
 168            printf "op1: %s\n", op if SLex.debug?
 169            @postproc.call(op, chrs)
 170          else
 171            nil
 172          end
 173        else
 174          ch = chrs.shift
 175          if node = @Tree[ch]
 176            if ret = node.match(chrs, op+ch)
 177              return ret
 178            else
 179              chrs.unshift ch
 180              if @postproc and @preproc.nil? || @preproc.call(op, chrs)
 181                printf "op2: %s\n", op.inspect if SLex.debug?
 182                ret = @postproc.call(op, chrs)
 183                return ret
 184              else
 185                return nil
 186              end
 187            end
 188          else
 189            chrs.unshift ch
 190            if @postproc and @preproc.nil? || @preproc.call(op, chrs)
 191              printf "op3: %s\n", op if SLex.debug?
 192              @postproc.call(op, chrs)
 193              return ""
 194            else
 195              return nil
 196            end
 197          end
 198        end
 199      end
 200  
 201      def match_io(io, op = "")
 202        if op == ""
 203          ch = io.getc
 204          if ch == nil
 205            return nil
 206          end
 207        else
 208          ch = io.getc_of_rests
 209        end
 210        if ch.nil?
 211          if @preproc.nil? || @preproc.call(op, io)
 212            printf "op1: %s\n", op if SLex.debug?
 213            @postproc.call(op, io)
 214          else
 215            nil
 216          end
 217        else
 218          if node = @Tree[ch]
 219            if ret = node.match_io(io, op+ch)
 220              ret
 221            else
 222              io.ungetc ch
 223              if @postproc and @preproc.nil? || @preproc.call(op, io)
 224                printf "op2: %s\n", op.inspect if SLex.debug?
 225                @postproc.call(op, io)
 226              else
 227                nil
 228              end
 229            end
 230          else
 231            io.ungetc ch
 232            if @postproc and @preproc.nil? || @preproc.call(op, io)
 233              printf "op3: %s\n", op if SLex.debug?
 234              @postproc.call(op, io)
 235            else
 236              nil
 237            end
 238          end
 239        end
 240      end
 241    end
 242  end
 243  
 244  if $0 == __FILE__
 245    #    Tracer.on
 246    case $1
 247    when "1"
 248      tr = SLex.new
 249      print "0: ", tr.inspect, "\n"
 250      tr.def_rule("=") {print "=\n"}
 251      print "1: ", tr.inspect, "\n"
 252      tr.def_rule("==") {print "==\n"}
 253      print "2: ", tr.inspect, "\n"
 254      
 255      print "case 1:\n"
 256      print tr.match("="), "\n"
 257      print "case 2:\n"
 258      print tr.match("=="), "\n"
 259      print "case 3:\n"
 260      print tr.match("=>"), "\n"
 261      
 262    when "2"
 263      tr = SLex.new
 264      print "0: ", tr.inspect, "\n"
 265      tr.def_rule("=") {print "=\n"}
 266      print "1: ", tr.inspect, "\n"
 267      tr.def_rule("==", proc{false}) {print "==\n"}
 268      print "2: ", tr.inspect, "\n"
 269      
 270      print "case 1:\n"
 271      print tr.match("="), "\n"
 272      print "case 2:\n"
 273      print tr.match("=="), "\n"
 274      print "case 3:\n"
 275      print tr.match("=>"), "\n"
 276    end
 277    exit
 278  end