Calculator - HolmesJJ/OOP-FP GitHub Wiki

Input.java

/**
 * Class Input reads a line from the system console (System.in).
 * It displays a numbered prompt.
 */

import java.util.Scanner;

public class Input {

    // Static members and methods
    private static int lineNo = 0;
    static Scanner sc = new Scanner(System.in).useDelimiter("\\n");

    public static Input readInput() {
        return new Input();
    }

    // Instance members and methods
    private final String line;

    private Input() {
        lineNo++;
	System.out.printf("[%d]=> ", lineNo);
	this.line = sc.next();
    }


    public String getLine() {
	return this.line;
    }

    public int getLineNum() {
	return this.lineNo;
    }
}

Result.java

/**
 * This class serves only to store the result of the calculation
 * in the form of a message string. A display method is provided
 * to print the message to console (System.out).
 */

public class Result {
    private final String message;
    
    public Result(String m) {
	this.message = m;
    }

    public void display() {
	System.out.println(message);
    }
}

Statement.java

/**
 * Class Statement is the workhorse of the calculator.
 * It initializes the hashtable to store the command and its associated
 * lambda function. To run the command, its name is used to lookup the table
 * to retrieve the lambda, which is then applied to the arguments.
 *
 * There is a lot of code to handle errors, which are due to:
 * (a) unknown command, (b) wrong type of arguments, (c) too many or too few
 * arguments. Such code clutters the main code and obscures the key idea.
 * There is room for improvement!
 */

import java.util.Scanner;
import java.util.function.Function;
import java.util.NoSuchElementException;
import java.util.InputMismatchException;
import java.util.Hashtable;

public class Statement {

    // static members and methods

    // This stores the function for each command
    private static Hashtable < String, Function < Double[], Double >> commandTable;

    // This stores the number of arguments for each command
    private static Hashtable < String, Integer > argsTable;

    public static Statement parse(Input input) {
        return new Statement(input.getLine());
    }

    /**
     * Error input, return 0.0
     * Accept a double array with 0 elements = 0 argument
     */
    private static final Function < Double[], Double >
        error = x - > 0.0;

    /**
     * Addition
     * Accept a double array with 2 elements = 2 arguments
     * Example: add 1 2
     */
    private static final Function < Double[], Double >
        addition = x - > x[0] + x[1];

    /**
     * Multiplication
     * Accept a double array with 2 elements = 2 arguments
     * Example: mult 3 4
     */
    private static final Function < Double[], Double >
        multiplication = x - > x[0] * x[1];

    /**
     * Reciprocal
     * Accept a double array with 1 element = 1 argument
     * Example: recip 5
     */
    private static final Function < Double[], Double >
        reciprocal = x - > 1.0 / x[0];

    /**
     * Percentage after Multiplication
     * Accept a double array with 2 elements = 2 arguments
     * Example: % 6 7
     */
    private static final Function < Double[], Double >
        percentage = x - > x[0] * x[1] / 100.0;

    // Initialization
    public static void initialize() {

        commandTable = new Hashtable < > ();
        argsTable = new Hashtable < > ();

        /**
         * Error input, return 0.0
         * Accept a double array with 0 elements = 0 argument
         */
        commandTable.put("err", error);
        argsTable.put("err", 0);

        /**
         * Addition
         * Accept a double array with 2 elements = 2 arguments
         */
        commandTable.put("add", addition);
        argsTable.put("add", 2);

        /**
         * Multiplication
         * Accept a double array with 2 elements = 2 arguments
         */
        commandTable.put("mult", multiplication);
        argsTable.put("mult", 2);

        /**
         * Reciprocal
         * Accept a double array with 1 element = 1 argument
         */
        commandTable.put("recip", reciprocal);
        argsTable.put("recip", 1);

        /**
         * Percentage after Multiplication
         * Accept a double array with 2 elements = 2 arguments
         */
        commandTable.put("%", percentage);
        argsTable.put("%", 2);
    }

    // Instance member and methods
    private String command;
    private Double[] arguments;
    private String message;

    // Input Method
    public Statement(String input) {

        /**
         * Input format: <command> <arg1> [<arg2>]
         *
         * Example:
         * add    1 2
         * mult   3 4
         * recip  5
         * %      6 7
         */
        Scanner sc = new Scanner(input);

        // Parse command
        String c = sc.next();
        // If the command is not err, add, mult, recip or %
        if (!commandTable.containsKey(c)) {
            this.command = "err";
            this.message = String.format("Bad command! %s", c);
            return;
        }
        this.command = c;

        // Parse arguments
        int numberArgs = argsTable.get(this.command);
        this.arguments = new Double[numberArgs];

        try {
            for (int i = 0; i < numberArgs; i++) {
                this.arguments[i] = sc.nextDouble();
            }
            if (sc.hasNext()) {
                this.command = "err";
                this.message = "Too many arguments!";
            }

        } catch (InputMismatchException e) {
            this.command = "err";
            this.message = "Bad arguments!";

        } catch (NoSuchElementException e) {
            this.command = "err";
            this.message = "Too few arguments!";
        }
    }

    public Result evaluate() {
        if (!this.command.equals("err")) {
            // commandTable.get(this.command): Function object
            // this.arguments: Double[] object
            double r = commandTable.get(this.command).apply(this.arguments);
            this.message = String.format("%f", r);
        }
        return new Result(this.message);
    }
}

Calc.java

/**
 * Calc.java implements a simple, command-line calculator.
 * User enters command in the form: <command> <arg1> <arg2>
 * Example: add 3 5

 * Currently, only 4 command are implemented: add, mult, recip, %,
 * denoting addition, multiplcation, reciprocal, and percentage, respectively.

 * To compile, put all the files in the same directory:
 * Calc.java, Input.java, Statement.java, Results.java

 * Then type:
 *    javac *.java
 *    java Calc
 */

import java.util.NoSuchElementException;

public class Calc {
    public static void main(String[] args) {
        // Initialize the calculator
        Statement.initialize();
        try {
            while (true) {
                Input input = Input.readInput();
                Statement statement = Statement.parse(input);
                Result result = statement.evaluate();
                result.display();
            }
        } catch (NoSuchElementException e) {
            // break out of while loop; end program
        }
    }
}
⚠️ **GitHub.com Fallback** ⚠️