naoppyの日記

自分が欲しいなと思った記事を書きます。

Brainfuckを中間言語に変換するやつ

最近、自作言語を作ってみたというような人々をよく見る

僕もBF系のクソ言語作るか~ということで、その前準備として中間言語に変換するやつを作ってみた

言語仕様?は+、-、>、<、は末尾に連続して続く数を付ける、ドット、カンマ、[、]、はそのまま、という感じです

あと無駄なコードは最適化されます

+++--は+1、>>><<>は>2といった感じ

内容

こんなBFコードが

+++++++++[>++++++++>+++++++++++>+++++<<<-]>.>++.++
+++++..+++.>-.------------.<++++++++.--------.+++.------.--------.>+.

こうなる

+9[>1+8>1+11>1+5<3-1]>1.>1+2.+7..+3.>1-1.-12.<1+8.-8.+3.-6.-8.>1+1.

フォルダ階層

C:/~/BFPREPROCESSOR/    
├─bfsource/
│      helloBF.bf
│      
├─bin/
│      FirstOptimize.class
│      
├─middleLang/
        helloBF.mbf

使い方

java bin/FirstOptimize helloBF.bf

のように打つとmiddleLang/にhelloBF.mbfというファイル名で変換される

実装

いつものコードコピペの垂れ流しである...

import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;

public class FirstOptimize {
    static Deque<Character> deq = new ArrayDeque<>(200);
    static BufferedWriter bw;

    public static void main(String[] args) {
        if (args.length < 1) {
            throw new IllegalArgumentException("needs sourcefile name");
        }
        String input = args[0];
        String filename = getFileName(input);
        try {
            bw = new BufferedWriter(new FileWriter("middleLang/" + filename + ".mbf"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("start");
        conversion(input);
        System.out.println("end");
    }

    static String getFileName(String input) {
        String s;
        int dotPlace = input.lastIndexOf(".bf");
        if (dotPlace == -1) {
            throw new IllegalArgumentException("this file is not bf file\nfilename example: helloworld.bf");
        }
        int srasyu = input.lastIndexOf("/");
        srasyu = Math.max(srasyu + 1, 0);
        s = input.substring(srasyu, dotPlace);
        return s;
    }

    static void conversion(String source) {
        try (FileReader r = new FileReader(source)) {
            char c;
            int i;
            while ((i = r.read()) != -1) {
                c = (char) i;
                addStack(c);
            }
            write();
            bw.flush();
            bw.close();
        } catch (Exception e) {
            System.err.println("ファイル読み込み中にエラー発生");
            e.printStackTrace();
        }
    }

    static void addStack(char c) {
        char[] validChars = { '+', '-', '>', '<', '.', ',', '[', ']' };
        boolean flag = true;
        for (char okC : validChars) {
            if (c == okC) {
                flag = false;
                break;
            }
        }
        if (flag)
            return;

        if (!deq.isEmpty()) {
            char lastItem = deq.getLast();
            if (c == '+' && lastItem == '-') {
                deq.pollLast();
                return;
            } else if (c == '-' && lastItem == '+') {
                deq.pollLast();
                return;
            } else if (c == '>' && lastItem == '<') {
                deq.pollLast();
                return;
            } else if (c == '<' && lastItem == '>') {
                deq.pollLast();
                return;
            } else if (c == lastItem && (c == '+' || c == '-' || c == '<' || c == '>')) {
                deq.offerLast(c);
            } else {
                write();
                deq.offerLast(c);
            }

        } else {
            deq.offerLast(c);
        }
    }

    static void write() {
        char c = deq.getLast();
        try {
            if (c == '[' || c == ']' || c == '.' || c == ',') {
                bw.write(String.valueOf(c));
            } else {
                bw.write(String.valueOf(c) + deq.size());
            }
        } catch (IOException e) {
            System.err.println("ファイル書き込み中にエラー");
            e.printStackTrace();
        }
        deq.clear();
    }
}

一応解説

最初はファイル名をえいえいする部分、後は一文字ずつ読んでいく

読んだ文字がBFの有効な8文字なら、スタックに積む

スタックの最後が+で今から積むのが-、など、最適化できるところは最適化する

違う種類が入れられると、ファイルに書き出す

簡単だね、次は中間言語からJavaバイトコードを生成したいけど、ちょっと自分の実力じゃダメそう...