Ruby StringScanner используется для лексизма: как получить номер строки? - PullRequest
5 голосов
/ 10 февраля 2012

Я использую StringScanner для лексического анализа следующим образом:

def next
 @scanner.skip(/\s+/)
 value,kind=nil,nil
 TOKEN_DEF.each{|tok,regex| (kind=tok;break) if @scanner.scan(regex)}
 return Token.new(kind,value,@line,@scanner.pos)
end

В первом приближении это работает хорошо, за исключением того, что я не могу понять, как теперь получить число @line.

Я прочитал документ, где begin_of_line?метод кажется подходящим, но я не могу понять, как его использовать.

Ответы [ 3 ]

1 голос
/ 13 февраля 2012

Я думаю, у меня есть простое решение.Вот оно:

def next
 @line+=1 while @scanner.skip(/\n/)
 @line+=1 if @scanner.bol?
 @scanner.skip(/\s+/)
 @line+=1 if @scanner.bol?
 @scanner.skip(/\s+/)
 return :eof if @scanner.eos?
 TOKEN_DEF.each { |tok,syntax| (kind=tok;break) if @scanner.scan(syntax)}
 return Token.new(kind,nil,@line,@scanner.pos)
end
1 голос
/ 28 июня 2013

Сохраните текст, который вы сканируете, в переменной и используйте 'count'

Я использую в своем коде следующее:

def current_line_number; @text[0..@scanner.pos].count("\n") + 1; end
1 голос
/ 11 февраля 2012

Этот код, похоже, не готов к работе, и наверняка где-то еще более изящное решение, он просто должен дать вам о чем подумать.

class Retry < StandardError
end

class TextScanner
  def initialize(filename)
    @lines = IO.readlines(filename)
    @fiber = Fiber.new do
      @lines.each_with_index do |line, index|
        @scanner = StringScanner.new(line)
        @scanner.skip(/\s+/)
        value, kind = nil, nil
        begin 
          got_token = false
          TOKEN_DEF.each do |tok, regex|
            if @scanner.scan(regex)
              Fiber.yield Token.new(tok, value, index, @scanner.pos)
              got_token = true
            end
          end
          raise Retry if got_token
        rescue Retry
          retry
        end
      end
      "fiber is finished"
    end
  end

  def next
    @fiber.resume
  end
end

text_scanner = TextScanner('sometextfile')
puts text_scanner.next #=> first token
puts text_scanner.next #=> second token
puts text_scanner.next #=> third token
...
puts text_scanner.next #=> "fiber is finished"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...