Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package ru.compscicenter.java2017.calculator;
- import ru.compscicenter.java2017.calculator.Node.DigitNode;
- import ru.compscicenter.java2017.calculator.Node.Node;
- import ru.compscicenter.java2017.calculator.Node.NodeBuilder;
- import java.rmi.UnexpectedException;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.regex.Pattern;
- // Takes String to constructor and parses it into tree.
- // On calculate calcultes the result value from the contained tree.
- public class Calculator {
- // Takes String and parses it with parse().
- public Calculator(String expression) throws UnexpectedException {
- root = parse(expression.replaceAll(" ", ""));
- }
- // Returns result from the contained tree.
- public double calculate() {
- return root.getValue();
- }
- private Node root;
- // Parses given string into tree.
- private static Node parse(String expression) throws IllegalArgumentException, UnexpectedException {
- Node node;
- // Trying to parse node as x+y+++ or x*y***.
- node = splitExpressionByDividers(expression, SplitExpressionHelper.getInstanceForAddition());
- if (node == null)
- node = splitExpressionByDividers(expression, SplitExpressionHelper.getInstanceForMultiplition());
- if (node != null)
- return node;
- // In this blocks expression is tried to be matched with simple patterns.
- else if (bracketsPatter.matcher(expression).matches()) {
- return parse(expression.substring(1, expression.length() - 1));
- }
- else if (unaryPlusPattern.matcher(expression).matches()) {
- return parse(expression.substring(1));
- }
- else if (unaryMinusPattern.matcher(expression).matches()) {
- return NodeBuilder.buildUnaryMinusNode().setNode(parse(expression.substring(1)));
- }
- else if (exponentPattern.matcher(expression).matches()) {
- String[] splitMaster = expression.split("\\^");
- return NodeBuilder.buildExponentNode().setNodes(parse(splitMaster[0]),
- parse(splitMaster[1]));
- }
- else if (sinPattern.matcher(expression).matches()) {
- return NodeBuilder.buildSinNode().setNode(parse(expression.substring("sin(".length(), expression.length() - 1)));
- }
- else if (cosPattern.matcher(expression).matches()) {
- return NodeBuilder.buildCosNode().setNode(parse(expression.substring("cos(".length(), expression.length() - 1)));
- }
- else if (absPattern.matcher(expression).matches()) {
- return NodeBuilder.buildAbsNode().setNode(parse(expression.substring("abs(".length(), expression.length() - 1)));
- }
- else if (digitPattern.matcher(expression).matches()) {
- String[] splitMaster = expression.split("E");
- if (splitMaster.length == 1) {
- return NodeBuilder.buildDigitNode().setValue(Double.parseDouble(splitMaster[0]));
- }
- return NodeBuilder.buildDigitNode().setValue(Integer.parseInt(splitMaster[0]) * Math.pow(10, Integer.parseInt(splitMaster[1])));
- }
- // If none of the patterns worked, then we do not know what we are dealing with.
- throw new UnexpectedException("Unknown problem while parsing: no matching pattern found!");
- }
- // Parses expression into list of expressions and then forms them into Node.
- // Takes SplitExpressionHelper to know what binary operation we expect to parse.
- private static Node splitExpressionByDividers(String expression, SplitExpressionHelper helper) throws UnexpectedException {
- int bracketsCounter = 0;
- int lastAddedIndex = 0;
- List<String> splitedExpression = new ArrayList<>();
- List<Boolean> wasFirstDivider = new ArrayList<>();
- // Dividing expression into list.
- for (int i = 1; i < expression.length(); ++i) {
- char symbol = expression.charAt(i);
- if (symbol == '(')
- bracketsCounter++;
- else if (symbol == ')') {
- if (bracketsCounter == 0)
- throw new IllegalArgumentException("Brackets don't match!");
- bracketsCounter--;
- }
- else if (symbol == helper.firstDivider && expression.charAt(i) != '(' && bracketsCounter == 0) {
- splitedExpression.add(expression.substring(lastAddedIndex, i));
- lastAddedIndex = i + 1;
- wasFirstDivider.add(true);
- }
- else if (symbol == helper.secondDivider && expression.charAt(i) != '(' && bracketsCounter == 0) {
- splitedExpression.add(expression.substring(lastAddedIndex, i));
- lastAddedIndex = i + 1;
- wasFirstDivider.add(false);
- }
- }
- splitedExpression.add(expression.substring(lastAddedIndex, expression.length()));
- // This rule should always be true.
- assert splitedExpression.size() - 1 == wasFirstDivider.size();
- // We recall what operation splited expression into list. Once we know we send it to the tree.
- if (splitedExpression.size() > 1) {
- Node lastNode;
- if (wasFirstDivider.get(0))
- lastNode = helper.getNodeFirstType().setNodes(parse(splitedExpression.get(0)), parse(splitedExpression.get(1)));
- else
- lastNode = helper.getNodeSecondType().setNodes(parse(splitedExpression.get(0)), parse(splitedExpression.get(1)));
- for (int i = 2; i < splitedExpression.size(); ++i) {
- if (wasFirstDivider.get(i - 1))
- lastNode = helper.getNodeFirstType().setNodes(lastNode, parse(splitedExpression.get(i)));
- else
- lastNode = helper.getNodeSecondType().setNodes(lastNode, parse(splitedExpression.get(i)));
- }
- return lastNode;
- }
- // If we found no correct spliting in expression we return null to indicate that.
- return null;
- }
- private static final Pattern bracketsPatter = Pattern.compile("\\(.*\\)");
- private static final Pattern unaryPlusPattern = Pattern.compile("\\+(((sin|cos|abs)?\\(.*\\))|([0-9]+(E(\\+|-)[0-9]*)?))");
- private static final Pattern unaryMinusPattern = Pattern.compile("-(((sin|cos|abs)?\\(.*\\))|([0-9]+(E(\\+|-)[0-9]*)?))");
- private static final Pattern sinPattern = Pattern.compile("sin\\(.*\\)");
- private static final Pattern cosPattern = Pattern.compile("cos\\(.*\\)");
- private static final Pattern absPattern = Pattern.compile("abs\\(.*\\)");
- private static final Pattern exponentPattern = Pattern.compile("(((sin|cos|abs)?\\(.*\\))|([0-9]+(E(\\+|-)[0-9]*)?))\\^(((sin|cos|abs)?\\(.*\\))|([0-9]+(E(\\+|-)[0-9]*)?))");
- private static final Pattern digitPattern = Pattern.compile("[0-9]+(E(\\+|-)[0-9]*)?");
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement