class Racc::GrammarFileScanner

Constants

CACHE
LEFT_TO_RIGHT
ReservedWord

Attributes

debug[RW]
epilogue[R]

Public Class Methods

new(str, filename = '-') click to toggle source
# File racc/grammarfileparser.rb, line 297
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

Public Instance Methods

lineno() click to toggle source
# File racc/grammarfileparser.rb, line 312
def lineno
  @lineno + 1
end
yylex() { |sym, tok| ... } click to toggle source
# File racc/grammarfileparser.rb, line 318
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

Private Instance Methods

atom_symbol(token) click to toggle source
# File racc/grammarfileparser.rb, line 398
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) click to toggle source
# File racc/grammarfileparser.rb, line 549
def get_quoted_re(left)
  term = Regexp.quote(LEFT_TO_RIGHT[left] || left)
  CACHE[left] ||= /\A[^#{term}\\]*(?:\\.[^\\#{term}]*)*#{term}/
end
literal_head?(pre, post) click to toggle source
# File racc/grammarfileparser.rb, line 505
def literal_head?(pre, post)
  (!pre || /[a-zA-Z_0-9]/n !~ pre[-1,1]) &&
      !post.empty? && /\A[\s\=]/n !~ post
end
next_line() click to toggle source
# File racc/grammarfileparser.rb, line 363
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) click to toggle source
# File racc/grammarfileparser.rb, line 510
def read(len)
  s = @line[0, len]
  @line = @line[len .. -1]
  s
end
reads(re) click to toggle source
# File racc/grammarfileparser.rb, line 516
def reads(re)
  m = re.match(@line) or return nil
  @line = m.post_match
  m[0]
end
scan_action() click to toggle source
# File racc/grammarfileparser.rb, line 429
def scan_action
  buf = ''
  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) click to toggle source
# File racc/grammarfileparser.rb, line 554
def scan_error!(msg)
  raise CompileError, "#{lineno()}: #{msg}"
end
scan_quoted(left, tag = 'string') click to toggle source
# File racc/grammarfileparser.rb, line 522
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() click to toggle source
# File racc/grammarfileparser.rb, line 418
def skip_comment
  @in_block = 'comment'
  until m = /\*\//.match(@line)
    next_line
  end
  @line = m.post_match
  @in_block = nil
end
yylex0() { |atom_symbol(s), intern| ... } click to toggle source
# File racc/grammarfileparser.rb, line 331
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