コンパイラ作成(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$
大丈夫そうだね。次回は本当に変数のサポートにするよ。多分、おそらく、きっと。