コンパイラ作成(30) 字句解析の機能追加

今回の目標

変数のサポートはちょっと考えてみたけど難しそうなんで別のことやることにしたよ。水は低い方に流れるってことで。

int main()
{
    printf("Answer is %d\n",answer_hex());
}

int answer_hex()
{
    //  Answer to the Ultimate Question of Life, the Universe, and Everything
    return 0x2a;
}

16進数とアンダーバーの対応だよ。

字句解析のバグ修正

本題に入る前にバグ修正から行くよ。

      # symbolの切り出し
      elsif m = @line[@idx,@line.length].match(/^(==|=|\+|\-|\*|\/|:|,|;|\(|\)|\{|\})/)  then
        str = m.to_s
        @idx += str.length
        return TK::SYMBOL, str
      end

こここの前も修正したんだけどまだ駄目だったよ。matchのパターンだけど()で括るところ間違えて[]にしてたよ。正規表現についてふんわりとしか理解してないからなあ。毎回、なんとなくこんな感じってやって、動いた動いたって済ませちゃうからいけないんだよなあ。

16進数リテラル

では機能追加。

      # numberの切り出し
      elsif m = @line[@idx,@line.length].match(/^0x\p{xdigit}+/) then
        str = m.to_s
        @idx += str.length
        str = str.to_i(16).to_s
        return TK::NUMBER, str

ちょっと悩んだけど10進数に変換して返すことにしたよ。トークンの種類を増やしたくなかったから。

アンダーバー

もういっちょ。

      # identifireの切り出し
      if m = @line[@idx,@line.length].match(/^[\p{alpha}|_]+/) then
        str = m.to_s
        @idx += str.length
        if @reservedword.include?(str) then
          return TK::RESERVE, str
        else
          return TK::ID, str
        end

正規表現あってるかな。ちょっと不安。これでアンダーバーを含んだIDを切り出せるはずなんだけどなあ。

動作テスト

それではテスト。

~/myc$ myc m5.myc
~/myc$ ./m5
Answer is 42
~/myc$

大丈夫そうだね。次回は本当に変数のサポートにするよ。多分、おそらく、きっと。