コンパイラ作成(3) Lexerクラス

# 字句解析
class Lexer
  # コンストラクタ
  def initialize(fname)
    @fname = fname    # ソースファイルのファイル名
    begin
      @io = File.open(@fname,"r")
    rescue SystemCallError => e
      puts %Q(class=[#{e.class}] message=[#{e.message}])
    end
    # 1行先読み
    @line = @io.gets
    @idx = 0
  end

  # ファイルクローズ
  def close
    @io.close
  end

  # テストメソッド
  def pfname
    puts "fname="+@fname
  end

  # テストメソッド
  def cat
    loop do
      if @line == nil then break end
      @line.chomp! # 改行文字を削除
      puts @line
      @line = @io.gets
    end
  end

  # トークンを一つ切り出す
  # kind, str = gettoken
  def gettoken
    str = ""

    # 空行、空白をスキップする
    loop do
      if @line == nil then return TK::EOF, str end
      @line.chomp! # 改行文字を削除
      if @line[@idx] then
        loop do
          if !@line[@idx] then
            break
          elsif @line[@idx].match(/\p{ascii}/) && !@line[@idx].match(/\s/) then
            break
          else
            @idx += 1
          end
        end
        if @line[@idx] then break end
      end
      @line = @io.gets
      @idx = 0
    end

    # tokenを切り出す
    if @line[@idx].match(/\p{ascii}/) then
      # identifireの切り出し
      if @line[@idx].match(/\p{alpha}/) then
        str += @line[@idx]
        @idx += 1
        loop do
          if !@line[@idx] then break end
          if !@line[@idx].match(/\p{ascii}/) then break end
          if !@line[@idx].match(/\p{alnum}/) then break end
          str += @line[@idx]
          @idx += 1
        end
        return TK::ID, str
      # numberの切り出し
      elsif @line[@idx].match(/\p{digit}/) then
        str += @line[@idx]
        @idx += 1
        loop do
          if !@line[@idx] then break end
          if !@line[@idx].match(/\p{ascii}/) then break end
          if !@line[@idx].match(/\p{digit}/) then break end
          str += @line[@idx]
          @idx += 1
        end
        return TK::NUMBER, str
      # stringの切り出し
      elsif @line[@idx] == "\"" then
        @idx += 1
        loop do
#          puts @line[@idx]
          if !@line[@idx] then break end
          if @line[@idx] == "\"" then
            @idx += 1
            break
          end
          str += @line[@idx]
          @idx += 1
        end
        return TK::STRING, str
      # operatorの切り出し
      elsif @line[@idx].match(/=|\+|\-|;|\(|\)|\{|\}/)  then
        str += @line[@idx]
        @idx += 1
        return TK::SYMBOL, str
      end
    end
    # tokenとして解釈不可能な文字
    str += @line[@idx]
    @idx += 1
    return TK::UNKNOWN, str
  end

end

ところどころコメント間違ってたりするなあ。あれもしかしてidentifireじゃなくてidentifierじゃね。こっぱずかしい。はてなブログのエディタに指摘されて気付いたよ。ちゃんと直しとこう。