/* * Copyright 2008 Reg Whitton * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.java.dev.eval; class Compiler { private final Tokeniser tokeniser; Compiler(String expression) { this.tokeniser = new Tokeniser(expression); } Operation compile() { Object expression = compile(null, null, 0, (char) 0, -1); /* * If expression is a variable name or BigDecimal constant value then we need to put into a NOP operation. */ if (expression instanceof Operation) { return (Operation) expression; } return Operation.nopOperationfactory(expression); } private Object compile(Object preReadOperand, Operator preReadOperator, int nestingLevel, char endOfExpressionChar, int terminatePrecedence) { Object operand = preReadOperand != null ? preReadOperand : getOperand(nestingLevel); Operator operator = preReadOperator != null ? preReadOperator : this.tokeniser.getOperator(endOfExpressionChar); while (operator != Operator.END) { if (operator == Operator.TERNARY) { Object operand2 = compile(null, null, nestingLevel, ':', -1); Object operand3 = compile(null, null, nestingLevel, endOfExpressionChar, -1); operand = Operation.tenaryOperationFactory(operator, operand, operand2, operand3); operator = Operator.END; } else { Object nextOperand = getOperand(nestingLevel); Operator nextOperator = this.tokeniser.getOperator(endOfExpressionChar); if (nextOperator == Operator.END) { /* We are at the end of the expression */ operand = Operation.binaryOperationfactory(operator, operand, nextOperand); operator = Operator.END; if (preReadOperator != null && endOfExpressionChar != 0) { /* The bracket also terminates an earlier expression. */ this.tokeniser.pushBack(Operator.END); } } else if (nextOperator.precedence <= terminatePrecedence) { /* * The precedence of the following operator effectively brings this expression to an end. */ operand = Operation.binaryOperationfactory(operator, operand, nextOperand); this.tokeniser.pushBack(nextOperator); operator = Operator.END; } else if (operator.precedence >= nextOperator.precedence) { /* The current operator binds tighter than any following it */ operand = Operation.binaryOperationfactory(operator, operand, nextOperand); operator = nextOperator; } else { /* * The following operator binds tighter so compile the following expression first. */ operand = Operation.binaryOperationfactory(operator, operand, compile(nextOperand, nextOperator, nestingLevel, endOfExpressionChar, operator.precedence)); operator = this.tokeniser.getOperator(endOfExpressionChar); if (operator == Operator.END && preReadOperator != null && endOfExpressionChar != 0) { /* The bracket also terminates an earlier expression. */ this.tokeniser.pushBack(Operator.END); } } } } return operand; } private Object getOperand(int nestingLevel) { Object operand = this.tokeniser.getOperand(); if (operand == Tokeniser.START_NEW_EXPRESSION) { operand = compile(null, null, nestingLevel + 1, ')', -1); } else if (operand instanceof Operator) { /* Can get unary operators when expecting operand */ return Operation.unaryOperationfactory((Operator) operand, getOperand(nestingLevel)); } return operand; } }