ミニキャン言語 発展課題 '>=' '<=' を実装した

はじめに

せっかく発展課題が実装できたので記事にしました。
ミニキャンでは実装後スライド発表だったので、それも少し意識しました。

前提

GitHub - yamaguchi1024/mc-lang-3: セキュリティミニキャンプ2019山梨 MC言語講義 第三回事前課題

こちらの通常課題が全て終わっているのが前提です(発展課題に取り組むのでもちろんですが)

実装

まず全体ソースを載せておきます。先にソースが見てみたいという場合はこちらを

github.com

Tokenを使う

今回>=<=+<となるべく近い実装にしたかったので、Tokenで実装しました。
追加した部分です。

lexer.h

enum Token {
    ...
    tok_sle = -8,
    tok_sge = -9,
}
codegen.h

    case tok_sle:
        L = Builder.CreateICmp(llvm::CmpInst::ICMP_SLE, L, R, "sletmp");
        return Builder.CreateIntCast(L, Builder.getInt64Ty(), true, "cast_i1_to_i64");
    case tok_sge:
        L = Builder.CreateICmp(llvm::CmpInst::ICMP_SGE, L, R, "sgetmp");
        return Builder.CreateIntCast(L, Builder.getInt64Ty(), true, "cast_i1_to_i64");
mc.cpp

    BinopPrecedence[tok_sle] = 10;
    BinopPrecedence[tok_sge] = 10;

これで他の演算子と近い形で実装できるようになりました。
これに伴って変更しなければいけいない部分がparser.hにあります。
GetTokPrecedenceのif (!isascii(CurTok))if (!isascii(CurTok) && CurTok != tok_sle && CurTok != tok_sge)に変更します。
+-などの演算子はgettokでその演算子のasciiを返すのですが、>=<=はtokenを返すのでisasciiでfalseになってしまいます。
だから条件を加えて-1をreturnしないようにします。

メイン処理

ここから実際に実装のための主な処理になります。
まずはソースを載せます。

if (lastChar == '>' || lastChar == '<') {
    tmpChar = lastChar;
    if (lastChar == '>') {
        lastChar = getNextChar(iFile);
        if (lastChar == '=') {
            tmpChar = tok_eof;
            lastChar = getNextChar(iFile);
            return tok_sge;
        }
    }
    if (lastChar == '<') {
        lastChar = getNextChar(iFile);
        if (lastChar == '=') {
            tmpChar = tok_eof;
            lastChar = getNextChar(iFile);
            return tok_sle;
        }
    }
    int tmp = lastChar;
    lastChar = tmpChar;
    tmpChar = tmp;
}

今回実装する演算子は必ず><が先に来るのでそれを条件に分岐します。
その後にもう1文字読み込んでそれが=ならtok_sgeかtok_sleをreturnします。

ここで一つ問題があって、読み込んだ文字が=出なかった場合次の処理に影響が出てしまいます。
なのでそこを調整してあげなければいけません。説明のために次の処理を先に載せます。

if (tmpChar != tok_eof) {
    lastChar = tmpChar;
} else {
    lastChar = getNextChar(iFile);
}

私はgettokの処理の最後にこの処理を書きました。
tmpCharには初期値としてtok_eofを入れてあります。(ここは別になんでもよい)
tmpCharには>, <の次の文字が保持されています。
tmpCharが初期値と異なる場合は次の文字が読まれているということなのでその値をlastCharに入れます。
もし次の文字を読んでいない場合は通常通り次の文字を読んで次の処理に移ります。
この分岐をすることによってトークンを先延ばしすることなく処理ができます。

以上、完成!

最後に

自分用メモと他人用の中間的な薄い内容になってしまったのは反省中です。
でも、ソースとこの記事でなんとなく>= , <=実装の方向性は見えると思います。
実装方法はなかなかゴリ押しな部分があるので、ご指摘お待ちしております。
次は負の数辺りを実装しようと思います。