123456789_123456789_123456789_123456789_123456789_

Class: Racc::GrammarFileScanner

Relationships & Source Files
Inherits: Object
Defined in: lib/racc/grammarfileparser.rb

Constant Summary

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Constructor Details

.new(str, filename = '-') ⇒ GrammarFileScanner

[ GitHub ]

  
# File 'lib/racc/grammarfileparser.rb', line 403

def initialize(str, filename = '-')
  @lines  = str.b.split(/\n|\r\n|\r/)
  @filename = filename
  @lineno = -1
  @line_head   = true
  @in_rule_blk = false
  @in_conv_blk = false
  @in_block = nil
  @epilogue = ''
  @debug = false
  next_line
end

Instance Attribute Details

#debug (rw)

[ GitHub ]

  
# File 'lib/racc/grammarfileparser.rb', line 422

attr_accessor :debug

#epilogue (readonly)

[ GitHub ]

  
# File 'lib/racc/grammarfileparser.rb', line 416

attr_reader :epilogue

Instance Method Details

#atom_symbol(token) (private)

[ GitHub ]

  
# File 'lib/racc/grammarfileparser.rb', line 505

def atom_symbol(token)
  if token == 'end'
    symbol = :END
    @in_conv_blk = false
    @in_rule_blk = false
  else
    if @line_head and not @in_conv_blk and not @in_rule_blk
      symbol = ReservedWord[token] || :SYMBOL
    else
      symbol = :SYMBOL
    end
    case symbol
    when :RULE then @in_rule_blk = true
    when :CONV then @in_conv_blk = true
    end
  end
  @line_head = false
  symbol
end

#get_quoted_re(left) (private)

[ GitHub ]

  
# File 'lib/racc/grammarfileparser.rb', line 656

def get_quoted_re(left)
  term = Regexp.quote(LEFT_TO_RIGHT[left] || left)
  CACHE[left] ||= /\A[^#{term}\\]*(?:\\.[^\\#{term}]*)*#{term}/
end

#lineno

[ GitHub ]

  
# File 'lib/racc/grammarfileparser.rb', line 418

def lineno
  @lineno + 1
end

#literal_head?(pre, post) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/racc/grammarfileparser.rb', line 612

def literal_head?(pre, post)
  (!pre || /[a-zA-Z_0-9]/n !~ pre[-1,1]) &&
      !post.empty? && /\A[\s\=]/n !~ post
end

#next_line (private)

[ GitHub ]

  
# File 'lib/racc/grammarfileparser.rb', line 469

def next_line
  @lineno += 1
  @line = @lines[@lineno]
  if not @line or /\A----/ =~ @line
    @epilogue = @lines.join("\n")
    @lines.clear
    @line = nil
    if @in_block
      @lineno -= 1
      scan_error! sprintf('unterminated %s', @in_block)
    end
    false
  else
    @line.sub!(/(?:\n|\r\n|\r)\z/, '')
    @line_head = true
    true
  end
end

#read(len) (private)

[ GitHub ]

  
# File 'lib/racc/grammarfileparser.rb', line 617

def read(len)
  s = @line[0, len]
  @line = @line[len .. -1]
  s
end

#reads(re) (private)

[ GitHub ]

  
# File 'lib/racc/grammarfileparser.rb', line 623

def reads(re)
  m = re.match(@line) or return nil
  @line = m.post_match
  m[0]
end

#scan_action (private)

[ GitHub ]

  
# File 'lib/racc/grammarfileparser.rb', line 536

def scan_action
  buf = String.new
  nest = 1
  pre = nil
  @in_block = 'action'
  begin
    pre = nil
    if s = reads(/\A\s+/)
      # does not set 'pre'
      buf << s
    end
    until @line.empty?
      if s = reads(/\A[^'"`{}%#\/\$]+/)
        buf << (pre = s)
        next
      end
      case ch = read(1)
      when '{'
        nest += 1
        buf << (pre = ch)
      when '}'
        nest -= 1
        if nest == 0
          @in_block = nil
          buf.sub!(/[ \t\f]+\z/, '')
          return buf
        end
        buf << (pre = ch)
      when '#'   # comment
        buf << ch << @line
        break
      when "'", '"', '`'
        buf << (pre = scan_quoted(ch))
      when '%'
        if literal_head? pre, @line
          # % string, regexp, array
          buf << ch
          case ch = read(1)
          when /[qQx]/n
            buf << ch << (pre = scan_quoted(read(1), '%string'))
          when /wW/n
            buf << ch << (pre = scan_quoted(read(1), '%array'))
          when /s/n
            buf << ch << (pre = scan_quoted(read(1), '%symbol'))
          when /r/n
            buf << ch << (pre = scan_quoted(read(1), '%regexp'))
          when /[a-zA-Z0-9= ]/n   # does not include "_"
            scan_error! "unknown type of % literal '%#{ch}'"
          else
            buf << (pre = scan_quoted(ch, '%string'))
          end
        else
          # operator
          buf << '||op->' if $raccs_print_type
          buf << (pre = ch)
        end
      when '/'
        if literal_head? pre, @line
          # regexp
          buf << (pre = scan_quoted(ch, 'regexp'))
        else
          # operator
          buf << '||op->' if $raccs_print_type
          buf << (pre = ch)
        end
      when '$'   # gvar
        buf << ch << (pre = read(1))
      else
        raise 'racc: fatal: must not happen'
      end
    end
    buf << "\n"
  end while next_line()
  raise 'racc: fatal: scan finished before parser finished'
end

#scan_error!(msg) (private)

Raises:

[ GitHub ]

  
# File 'lib/racc/grammarfileparser.rb', line 661

def scan_error!(msg)
  raise CompileError, "#{lineno()}: #{msg}"
end

#scan_quoted(left, tag = 'string') (private)

[ GitHub ]

  
# File 'lib/racc/grammarfileparser.rb', line 629

def scan_quoted(left, tag = 'string')
  buf = left.dup
  buf = "||#{tag}->" + buf if $raccs_print_type
  re = get_quoted_re(left)
  sv, @in_block = @in_block, tag
  begin
    if s = reads(re)
      buf << s
      break
    else
      buf << @line
    end
  end while next_line()
  @in_block = sv
  buf << "<-#{tag}||" if $raccs_print_type
  buf
end

#skip_comment (private)

[ GitHub ]

  
# File 'lib/racc/grammarfileparser.rb', line 525

def skip_comment
  @in_block = 'comment'
  until m = /\*\//.match(@line)
    next_line
  end
  @line = m.post_match
  @in_block = nil
end

#yylex(&block)

[ GitHub ]

  
# File 'lib/racc/grammarfileparser.rb', line 424

def yylex(&block)
  unless @debug
    yylex0(&block)
  else
    yylex0 do |sym, tok|
      $stderr.printf "%7d %-10s %s\n", lineno(), sym.inspect, tok.inspect
      yield [sym, tok]
    end
  end
end

#yylex0 {|nil| ... } (private)

Yields:

  • (nil)
[ GitHub ]

  
# File 'lib/racc/grammarfileparser.rb', line 437

def yylex0
  begin
    until @line.empty?
      @line.sub!(/\A\s+/, '')
      if /\A\#/ =~ @line
        break
      elsif /\A\/\*/ =~ @line
        skip_comment
      elsif s = reads(/\A[a-zA-Z_]\w*/)
        yield [atom_symbol(s), s.intern]
      elsif s = reads(/\A\d+/)
        yield [:DIGIT, s.to_i]
      elsif ch = reads(/\A./)
        case ch
        when '"', "'"
          yield [:STRING, eval(scan_quoted(ch))]
        when '{'
          lineno = lineno()
          yield [:ACTION, SourceText.new(scan_action(), @filename, lineno)]
        else
          if ch == '|'
            @line_head = false
          end
          yield [ch, ch]
        end
      else
      end
    end
  end while next_line()
  yield nil
end