##### 数式計算機

- 概要
- 使い方
- ダウンロード
- JavaDoc
- ライセンス
- 開発環境

##### Project Documentation

- About 数式計算機
- Downloads
- Project Info
- Project Reports
- Development Process

## 使い方

数式の解析、計算は、以下の段階を経て行われます。

1. 構文解析器による、文字列で表された通常の数式から抽象構文木の構築(構文解析)。
2. コンパイラーによる、抽象構文木から命令列への変換(コンパイル)。
3. 計算機による、命令列の実行(計算)。

### 構文解析

構文解析はParserクラスによって行われます。Parserクラスは、文字列を読み込み、構文規則に従って抽象構文木を構築します。

    Parser parser = new Parser();
    Node Node = parser.parse("1 + 2"); // top level node

得られたNodeインスタンスが、抽象構文木の最上位ノードです。全てのノードはNodeクラスで表されます。実際は各構文規則に対応するノードのクラスが有り、それらのインスタンスで構成されています。

抽象構文木は、組替えたり(TODO: 0.1.xでは難しい。簡単にできるようにする)、自分で構築する事ができます。

    IntegerLiteralNode value1 = new IntegerLiteralNode("1");
    IntegerLiteralNode value2 = new IntegerLiteralNode("2");
    AdditiveExpressionNode.OperatorNode addOpe = new AdditiveExpressionNode.AddNode();
    AdditiveExpressionNode addExp = new AdditiveExpressionNode(value1, addOpe, value2);

    Node expNode = new ExpressionStatementNode(addExp); // top level node

構文規則は以下の通りです(TODO: JavaCC構文規則を記載する)。

### コンパイル

コンパイルはCompilerクラスによって行われます。Compilerクラスは、Nodeインスタンスを読み込み、命令列へ変換します。

    Compiler compiler = new Compiler();
    CommandList cl = compiler.compile(node); // command list

得られたCommandListインスタンスが、命令列を表します。CommandListインスタンスはCommandインスタンスのコンテナであり、Commandクラスは1つの命令を表します。

命令列は、組替えたり、自分で構築する事ができます(TODO: イミュータブルじゃないし、ちゃんとListを実装する)。

    Command[] commands = new Command[3];
    commands[0] = new PushStackCommand(1);
    commands[1] = new PushStackCommand(2);
    commands[2] = new AddCommand();

    CommandList cl = new CommandList(commands);

### 計算

計算はComputerクラスによって行われます。Computerクラスは、命令列を読み込み、実行します。

    Computer comp = new Computer();
    double value = comp.compute(cl);

命令列ではなく文字列を読み込ませることで、構文解析、コンパイル、計算を一度にすることができます。

    Computer comp = new Computer();
    double value = comp.compute("1 + 2");

得られたdouble値が計算結果です。計算は、全てdouble型で行われます。

### 変数

数式中で変数を使用することができます。以下のように使用します。

    Computer comp = new Computer();
    comp.setVariable("x", 10);
    comp.setVariable("y", 0);

    double result = comp.compute("y = x * 2 + 1"); // 11
    double xValue = comp.getVariable("x"); // 10
    double yValue = comp.getVariable("y"); // 11

数式中で使用する変数は、計算前に定義する必要があります。変数の定義はsetVariable()メソッドで行います。今回の数式で使用されたxのようにあらかじめ値を設定します。yのように数式中で設定される場合は、適当な値で構いません。変数の値は、計算前でも後でも、getVariable()メソッドで取得することが出来ます。計算後ならば、計算中で代入された値に変更されています。

### 関数

数式中で関数を呼び出すことが出来ます。以下のように使用します。

    class SinFunction implements Function {
        double call(double[] arguments) {
            return Math.sin(arguments[0]);
        }
    }

    Computer comp = new Computer();
    comp.addFunction("sin", new SinFunction());
    comp.setVariable("PI", Math.PI);

    double result = comp.compute("sin(0.5 * PI)"); // about 1

数式中で使用する関数は、計算前に定義する必要があります。定義は、Functionインターフェイスを実装し、そのインスタンスをaddFunction()メソッドに指定します。call()メソッドは、数式中で指定された引数がargumentsに渡されるので、それらを計算し、返します。

### 演算子

以下の演算子をサポートします。

+, -, *, /, %
  加算、減算、乗算、除算、剰余算演算子。
>, <, >=, <=, ==, !=
  比較演算子。真の場合は1、偽の場合は0を返します。
++, --
  前置、後置インクリメント、デクリメント。
&, |, ^
  論理積、論理和、排他的論理和。
&&, ||
  条件論理積、条件論理和。
<<, >>, >>>
  シフト演算子。
?:
  条件演算子。
=, +=, -=, *=, /=, %=, &=, |=, ^=, <=, >>=, >>>=
  代入演算子。