2 Copyright 2011 frank asseg
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
8 http://www.apache.org/licenses/LICENSE-2.0
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
17 package de.congrace.exp4j;
19 import java.util.Stack;
22 * {@link Token} for Operations like +,-,*,/,% and ^
24 * @author fas@congrace.de
26 class OperatorToken extends CalculationToken {
29 * the valid {@link Operation}s for the {@link OperatorToken}
31 * @author fas@congrace.de
34 ADDITION(1, true), SUBTRACTION(1, true), MULTIPLICATION(2, true), DIVISION(2, true), MODULO(2, true), EXPONENTIATION(3, false), UNARY_MINUS(4, false), UNARY_PLUS(
36 private final int precedence;
37 private final boolean leftAssociative;
39 private Operation(int precedence, boolean leftAssociative) {
40 this.precedence = precedence;
41 this.leftAssociative = leftAssociative;
46 * return a corresponding {@link Operation} for a symbol
49 * the symbol of the operation
50 * @return the corresponding {@link Operation}
52 static Operation getOperation(char c) {
55 return Operation.ADDITION;
57 return Operation.SUBTRACTION;
59 return Operation.MULTIPLICATION;
61 return Operation.DIVISION;
63 return Operation.EXPONENTIATION;
65 return Operation.UNARY_MINUS;
67 return Operation.MODULO;
73 static boolean isOperator(char c) {
74 return getOperation(c) != null;
77 private final Operation operation;
80 * construct a new {@link OperatorToken}
83 * the symbol (e.g.: '+')
85 * the {@link Operation} of this {@link Token}
87 OperatorToken(String value, Operation operation) {
89 this.operation = operation;
93 * apply the {@link Operation}
96 * the doubles to operate on
97 * @return the result of the {@link Operation}
98 * @throws UnparsableExpressionException
100 public Variable applyOperation(Variable... values) {
102 values = expandVariables(values);
104 double[] inputs = new double[values.length];
105 switch (values[0].getPrimary()){
108 for (int i = 0; i<values.length; i++){
109 inputs[i] = values[i].getDoubleValue();
111 double result = applyOperation(inputs);
112 return new Variable("double " + operation.name()+" result, ", result);
115 int maxLength = values[0].getArrayValue().length;
116 double[] results = new double[maxLength];
117 for (int i = 0; i< maxLength; i++){
118 // assemble the array of input values
119 for (int j = 0; j<values.length; j++){
120 inputs[j] = values[j].getArrayValue()[i];
122 results[i] = applyOperation(inputs);
124 //System.out.println("Done applying operation "+operation.name());
125 return new Variable("array " + operation.name()+" result, ", results);
128 return new Variable("Invalid");
132 private double applyOperation(double[] values){
134 //System.out.println("Applying "+operation.toString()+" to values starting "+values[0]);
138 return values[0] + values[1];
140 return values[0] - values[1];
142 return values[0] * values[1];
144 return Math.pow(values[0], values[1]);
146 return values[0] / values[1];
152 return values[0] % values[1];
159 public boolean equals(Object obj) {
160 if (obj instanceof OperatorToken) {
161 final OperatorToken t = (OperatorToken) obj;
162 return t.getValue().equals(this.getValue());
167 int getOperandCount() {
185 * get the {@link Operation} of this {@link Token}
187 * @return the {@link Operation}
189 Operation getOperation() {
193 int getPrecedence() {
194 return operation.precedence;
198 public int hashCode() {
199 return getValue().hashCode();
203 * check if the operation is left associative
205 * @return true if left associative, otherwise false
207 boolean isLeftAssociative() {
208 return operation.leftAssociative;
212 void mutateStackForCalculation(Stack<Variable> stack, VariableSet variables) {
213 if (this.getOperandCount() == 2) {
214 final Variable n2 = stack.pop();
215 final Variable n1 = stack.pop();
216 stack.push(this.applyOperation(n1, n2));
217 } else if (this.getOperandCount() == 1) {
218 final Variable n1 = stack.pop();
219 stack.push(this.applyOperation(n1));
224 void mutateStackForInfixTranslation(Stack<Token> operatorStack, StringBuilder output) {
226 while (!operatorStack.isEmpty() && (before = operatorStack.peek()) != null && (before instanceof OperatorToken || before instanceof FunctionToken)) {
227 if (before instanceof FunctionToken) {
229 output.append(before.getValue()).append(" ");
231 final OperatorToken stackOperator = (OperatorToken) before;
232 if (this.isLeftAssociative() && this.getPrecedence() <= stackOperator.getPrecedence()) {
233 output.append(operatorStack.pop().getValue()).append(" ");
234 } else if (!this.isLeftAssociative() && this.getPrecedence() < stackOperator.getPrecedence()) {
235 output.append(operatorStack.pop().getValue()).append(" ");
241 operatorStack.push(this);