LoginSignup
4
2

More than 5 years have passed since last update.

JavaでREPL、JavaScriptを利用して計算機インタプリタへ。

Posted at

「JavaでREPLを作る。」のREPLBaseを改良。
JavaScriptを利用して計算機インタプリタを作る。

replCalc1.png

JavaからJavaScript実行はScriptEngineManagerとScriptEngineを使用します。

JavaScript実行
ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
ScriptEngine scriptEngine = scriptEngineManager.getEngineByName("JavaScript");
scriptEngine.eval("print(eval(¥"1+1¥"))")

REPLBase.java
ベースクラス化しました。
起動メッセージ、プロンプト等を派生側で設定可能にしました。
compile()メソッドを抽象メソッドにし、派生側で実装するようにしました。

REPLBase.java
package replbase;

import java.io.IOException;
import java.io.PrintWriter;
import jline.ConsoleReader;

abstract public class REPLBase {

    protected String COMMAND = ":";
    protected String PROMPT_READLINE = ">>> ";
    protected String PROMPT_INCOMPLETE = "... ";
    protected String START_MESSAGE = "Welcome to REPLBase.(JRE " + System.getProperty("java.runtime.version") + ")\n" +
                                       "Type :help for help, :quit for quit\n";
    private ConsoleReader consoleReader;

    enum STATUS {
        READLINE,
        INCOMPLETE,
        QUIT
    }
    private STATUS status = STATUS.READLINE;

    public void start() {
        try(PrintWriter printwriter = new PrintWriter(System.out);) {
            consoleReader = new ConsoleReader(System.in, printwriter);
            if((START_MESSAGE != null) && (START_MESSAGE.isEmpty() == false)) {
                printString(START_MESSAGE);
            }
            while(status != STATUS.QUIT) {
                String input = readLine();
                analyze(input);
            }
        }
        catch(IOException exception) {
            System.err.println(exception);
        }
    }

    private String readLine() throws IOException{
        String prompt = status == STATUS.READLINE ? PROMPT_READLINE : PROMPT_INCOMPLETE;
        String input = consoleReader.readLine(prompt);
        return input;
    }

    private void analyze(String input) throws IOException {
        if((status != STATUS.INCOMPLETE) &&
           (input.startsWith(COMMAND) == true)) {
            command(input);
        }
        else {
            compile(input);
        }
    }

    abstract protected void compile(String input);

    private void command(String input) {
        String command = input.replaceFirst(COMMAND, "");
        switch(command) {
            case "help":
                printString("Available commands:\n" +
                              ":help    show this help\n" +
                              ":quit    exit the interpreter\n");
                break;
            case "quit":
                status = STATUS.QUIT;
                break;
            default:
                printString("Unknown command\n" +
                              "Type :help for help\n");
                break;
        }
    }

    public void printString(String message) {
        try {
            if((message != null) &&
               (message.isEmpty() == false)) {
                consoleReader.printString(message);
            }
        }
        catch(IOException exception) {
            System.err.println(exception);
        }
    }

}

REPLCalc.java
計算機インタプリタ実装クラス。
JavaScriptのeval()メソッドを使用していますので、計算機ロジックを組む必要はありません。
画像を見ていただければ分かりますが、変数を使うことも可能です。

REPLCalc.java
package replcalc;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import replbase.REPLBase;

public class REPLCalc extends REPLBase {

    private final ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
    private final ScriptEngine scriptEngine = scriptEngineManager.getEngineByName("JavaScript");

    public static void main(String[] args) {
        REPLCalc replCalc = new REPLCalc();
        replCalc.PROMPT_READLINE = "[Calc] ";
        replCalc.START_MESSAGE = "Welcome to Calc.(Used JavaScript Engine)\n" +
                                   "Type :help for help, :quit for quit\n";
        replCalc.start();
    }

    @Override
    public void compile(String input) {
        try {
            scriptEngine.eval("print(eval(\"" + input + "\"))");
        }
        catch(ScriptException exception) {
            printString(exception.getMessage() + "\n");
        }
    }

}

compile()メソッドを「scriptEngine.eval(input);」に変更すると、JavaScriptインタプリタになります。
if文や関数定義・実行等が可能です。
インタプリタ内からJavaをコールも可能です。
JDKに用意されているjjsコマンドと変わりませんが。。。
replCalc2_js.png
replCalc3_js.png
replCalc_js4.png

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2