/*
* $Id: FunctionType4.java,v 1.3 2009-02-12 13:53:59 tomoke Exp $
*
* Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
* Santa Clara, California 95054, U.S.A. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.sun.pdfview.function;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.*;
import com.sun.pdfview.PDFObject;
import com.sun.pdfview.PDFParseException;
/**
* <p>A PostScript function is represented as a stream containing code
* written in a small subset of the PostScript language.
* This reference is taken from the (3200-1:2008:7.10.5)<p>
*
* http://www.adobe.com/devnet/acrobat/pdfs/adobe_supplement_iso32000.pdf
* </p>
*/
public class FunctionType4 extends PDFFunction {
/** the set of all Operations we support. These operations are defined
* in Appendix B - Operators.*/
private static HashSet<Operation> operationSet = null;
/** the list of tokens and sub-expressions. */
private LinkedList tokens = new LinkedList();
/** the stack of operations. The stack contents should all be Comparable. */
private LinkedList<Object> stack = new LinkedList<Object>();
/** Creates a new instance of FunctionType4 */
protected FunctionType4() {
super(TYPE_4);
if (operationSet == null) {
initOperations();
}
}
/**
* Initialize the operations that we can perform.
*/
private void initOperations() {
/** these operators consider the left hand arguments as deeper in
* the stack than the right hand arguments, thus the right-hand is
* is the top of the stack and is popped first.
*
* Operation details in PostScript Language Reference Manual:
* http://www.adobe.com/products/postscript/pdfs/PLRM.pdf
* Chapter 8 - Operator Details
*/
if (operationSet == null) {
operationSet = new HashSet<Operation>();
// Arithmetic Operators
operationSet.add(new Operation("abs") {
/**
* <i>num1</i> <b>abs</b> <i>num2</i> <p>
*
* The type of the result is the same as the type of num1,
* unless num1 is the smallest (most negative) integer,
* in which case the result is a real number.<p>
*
* errors: stackunderflow, typecheck
*/
void eval() {
pushDouble(Math.abs(popDouble()));
}
});
operationSet.add(new Operation("add") {
/**
* <i>num1 num2</i> <b>add</b> <i>sum</i> <p>
*
* If both operands are integers and the result is
* within integer range, the result is an integer;
* otherwise, the result is a real number.<p>
*
* errors: stackunderflow, typecheck, undefinedresult
*/
void eval() {
pushDouble(popDouble() + popDouble());
}
});
operationSet.add(new Operation("atan") {
/**
* <i>num den</i> <b>atan</b> <i>angle</i> <p>
*
* returns the angle (in degress between
* 0 and 360) whose tangent is num divided by den.
* Either num or den may be 0, but not both. The signs
* of num and den determine the quadrant in which the
* result will lie: positive num yeilds a result in the
* positive y plane, while a positive den yeilds a result in
* the positive x plane. The result is a real number.<p>
*
* errors: stackunderflow, typecheck, undefinedresult
*/
void eval() {
double den = popDouble();
double num = popDouble();
if (den == 0.0) {
pushDouble(90.0);
} else {
pushDouble(Math.toDegrees(Math.atan(num / den)));
}
}
});
operationSet.add(new Operation("ceiling") {
/**
* <i>num1</i> <b>ceiling</b> <i>num2</i> <p>
*
* returns the least integer value greater than or equal
* to num1. The type of the result is the same as the type
* of the operand. <p>
*
* errors: stackunderflow, typecheck
*/
void eval() {
pushDouble(Math.ceil(popDouble()));
}
});
operationSet.add(new Operation("cvi") {
/**
* <i>num</i> <b>cvi</b> <i>int</i> <u>or</u> <i>string</i> <b>cvi</b> <i>int</i> <p>
*
* takes an integer, real, or string and produces an
* integer result. If the operand is an integer, cvi
* simply returns it. If the operand is a real number,
* it truncates any fractional part (that is, rounds
* it toward 0) and converts it to an integer.
* If the operand is a string, cvi invokes the equivalent
* of the token operator to interpret the characters
* of the string as a number according to the PostScript
* syntax rules. If that number is a real number, cvi converts
* it to an integer.
* A rangecheck error occurs if a real number is too
* large to convert to an integer. <p>
*
* errors: invalidaccess, rangecheck, stackunderflow,
* syntaxError, typecheck,
*/
void eval() {
pushDouble((double) ((int) popDouble()));
}
});
operationSet.add(new Operation("cvr") {
/**
* <i>num</i> <b>cvr</b> <i>real</i> <u>or</u> <i>string</i> <b>cvr</b> <i>real</i> <p>
*
* (convert to real) takes an integer, real, or string
* object and produces a real result. If the operand
* is an integer, cvr converts it to a real number.
* If the operand is a real number, cvr simply returns it.
* If the operand is a string, cvr invokes the equivalent
* of the token operator to interpret the characters of
* the string as a number according to the PostScript
* syntax rules. If that number is an integer, cvr converts
* it to a real number. <p>
*
* errors: invalidaccess, limitcheck, stackunderflow,
* syntaxerror, typecheck, undefinedresult
*/
void eval() {
// YOUR CODE IN THIS SPACE
}
});
operationSet.add(new Operation("div") {
/**
* <i>num1 num2</i> <b>div</b> <i>quotient</i> <p>
*
* divides num1 by num2, producing a result that is
* always a real number even if both operands are integers.
* Use idiv instead if the operands are integers and an
* integer result is desired. <p>
*
* errors: stackunderflow, typecheck, undefinedresult
*/
void eval() {
double num2 = popDouble();
double num1 = popDouble();
pushDouble(num1 / num2);
}
});
operationSet.add(new Operation("exp") {
/**
* <i>base exponent</i> <b>exp</b> <i>real</i> <p>
*
* raises base to the exponent power. The operands may be
* either integers or real numbers. If the exponent has a
* fractional part, the result is meaningful only if the
* base is nonnegative. The result is always a real number. <p>
*
* errors: stackunderflow, typecheck, undefinedresult
*/
void eval() {
double exponent = popDouble();
double base = popDouble();
pushDouble(Math.pow(exponent, base));
}
});
operationSet.add(new Operation("floor") {
/**
* <i>num1</i> <b>floor</b> <i>num2</i> <p>
*
* returns the greatest integer value less than or equal
* to num1. The type of the result is the same as the type
* of the operand. <p>
*
* errors: stackunderflow, typecheck
*/
void eval() {
pushDouble(Math.floor(popDouble()));
}
});
operationSet.add(new Operation("idiv") {
/**
* <i>int1 int2</i> <b>idiv</b> <i>quotient</i> <p>
*
* divides int1 by int2 and returns the integer part
* of the quotient, with any fractional part discarded.
* Both operands of idiv must be integers and the result
* is an integer. <p>
*
* stackunderflow, typecheck, undefinedresult
*/
void eval() {
long int2 = popLong();
long int1 = popLong();
pushLong(int1 / int2);
}
});
operationSet.add(new Operation("ln") {
/**
* <i>num</i> <b>ln</b> <i>real</i> <p>
*
* returns the natural logarithm (base e) of num.
* The result is a real number. <p>
*
* errors: rangecheck, stackunderflow, typecheck
*/
void eval() {
pushDouble(Math.log(popDouble()));
}
});
operationSet.add(new Operation("log") {
/**
* <i>num</i> <b>log</b> <i>real</i> <p>
*
* returns the common logarithm (base 10) of num.
* The result is a real number. <p>
*
* errors: rangecheck, stackunderflow, typecheck
*/
void eval() {
pushDouble(Math.log10(popDouble()));
}
});
operationSet.add(new Operation("mod") {
/**
* <i>int1 int2</i> <b>mod</b> <i>remainder</i> <p>
*
* returns the remainder that results from
* dividing int1 by int2. The sign of the result
* is the same as the sign of the dividend int1.
* Both operands must be integers and the result
* is an integer. <p>
*
* errors: stackunderflow, typecheck, undefinedresult
*/
void eval() {
long int2 = popLong();
long int1 = popLong();
pushLong(int1 % int2);
}
});
operationSet.add(new Operation("mul") {
/**
* <i>num1 num2</i> <b>mul</b> <i>product</i> <p>
*
* returns the product of num1 and num2.
* If both operands are integers and the result
* is within integer range, the result is an integer;
* otherwise, the result is a real number. <p>
*
* errors: stackunderflow, typecheck, undefinedresult
*/
void eval() {
pushDouble(popDouble() * popDouble());
}
});
operationSet.add(new Operation("neg") {
/**
* <i>num1</i> <b>neg</b> <i>num2</i> <p>
*
* returns the negative of num1. The type of the result
* is the same as the type of num1 unless num1 is the
* smallest (most negative) integer, in which case the
* result is a real number. <p>
*
* errors: stackunderflow, typecheck
*/
void eval() {
pushDouble(-popDouble());
}
});
operationSet.add(new Operation("round") {
/**
* <i>num1</i> <b>round</b> <i>num2</i> <p>
*
* returns the integer value nearest to num1.
* If num1 is equally close to its two nearest
* integers, round returns the greater of the two.
* The type of the result is the same as
* the type of the operand. <p>
*
* errors: stackunderflow, typecheck
*/
void eval() {
pushLong(Math.round(popDouble()));
}
});
operationSet.add(new Operation("sin") {
/**
* <i>angle</i> <b>sin</b> <i>real</i> <p>
*
* returns the sine of angle, which is interpreted as an
* angle in degrees. The result is a real number. <p>
*
* errors: stackunderflow, typecheck
*/
void eval() {
double radians = Math.toRadians(popDouble());
pushDouble(Math.toDegrees(Math.sin(radians)));
}
});
operationSet.add(new Operation("sqrt") {
/**
* <i>num</i> <b>sqrt</b> <i>real</i> <p>
*
* returns the square root of num, which must be a
* nonnegative number. The result is a real number. <p>
*
* errors: rangecheck, stackunderflow, typecheck
*/
void eval() {
pushDouble(Math.sqrt(popDouble()));
}
});
operationSet.add(new Operation("sub") {
/**
* <i>num1 num2</i> <b>sub</b> <i>difference</i> <p>
*
* returns the result of subtracting num2 from num1.
* If both operands are integers and the result is within
* integer range, the result is an integer; otherwise,
* the result is a real number. <p>
*
* errors: stackunderflow, typecheck, undefinedresult
*/
void eval() {
double num2 = popDouble();
double num1 = popDouble();
pushDouble(num1 - num2);
}
});
operationSet.add(new Operation("truncate") {
/**
* <i>num1</i> <b>truncate</b> <i>num2</i> <p>
*
* truncates num1 toward 0 by removing its fractional part.
* The type of the result is the same as the type of the
* operand. <p>
*
* errors: stackunderflow, typecheck
*/
void eval() {
double num1 = popDouble();
pushDouble(((double) ((long) num1) - num1));
}
});
// Relational, boolean, and bitwise operators
operationSet.add(new Operation("and") {
/**
* <i>bool1|int1 bool2|int2</i> <b>and</b> <i>bool3|int3</i> <p>
*
* returns the logical conjunction of the operands
* if they are boolean. If the operands are integers,
* and returns the bitwise "and" of their binary
* representations. <p>
*
* errors: stackunderflow, typecheck
*/
void eval() {
pushLong(popLong() & popLong());
}
});
operationSet.add(new Operation("bitshift") {
/**
* <i>int1 <i>shift</i> <b>bitshift</b> <i>int2</i> <p>
*
* shifts the binary representation of int1 left by
* shift bits and returns the result. Bits shifted out
* are lost; bits shifted in are 0. If shift is negative,
* a right shift by –shift bits is performed.
* This operation produces an arithmetically correct
* result only for positive values of int1.
* Both int1 and shift must be integers. <p>
*
* errors: stackunderflow, typecheck
*/
void eval() {
long shift = popLong();
long int1 = popLong();
pushLong(int1 << shift);
}
});
operationSet.add(new Operation("eq") {
/**
* <i>any1 <i>any2</i> <b>eq</b> <i>bool</i> <p>
*
* pops two objects from the operand stack and pushes\
* true if they are equal, or false if not.
* The definition of equality depends on the types of
* the objects being compared.
* Simple objects are equal if their types and values
* are the same. Strings are equal if their lengths and
* individual elements are equal. Other composite objects
* (arrays and dictionaries) are equal only if they share
* the same value. Separate values are considered unequal,
* even if all the components of those values are the
* same.
* This operator performs some type conversions.
* Integers and real numbers can be compared freely:
* an integer and a real number representing the same
* mathematical value are considered equal by eq.
* Strings and names can likewise be compared freely:
* a name defined by some sequence of characters is equal
* to a string whose elements are the same sequence of
* characters.
* The literal/executable and access attributes of
* objects are not considered in comparisons
* between objects. <p>
*
* errors: invalidaccess, stackunderflow
*/
void eval() {
pushBoolean(popObject().equals(popObject()));
}
});
operationSet.add(new Operation("false") {
/**
* <b>false</b> <i>false</i> <p>
*
* pushes a boolean object whose value is false on the
* operand stack. false is not an operator; it is a name in
* systemdict associated with the boolean value false. <p>
*
* errors: stackoverflow
*/
void eval() {
pushBoolean(false);
}
});
operationSet.add(new Operation("ge") {
/**
* <i>num1 num2</i> <b>ge</b> <i>bool</i> <p>
*
* pops two objects from the operand stack and pushes true
* if the first operand is greater than or equal to the second,
* or false otherwise. If both operands are numbers,
* ge compares their mathematical values. If both operands
* are strings, ge compares them element by element, treating
* the elements as integers in the range 0 to 255, to determine
* whether the first string is lexically greater than or equal
* to the second. If the operands are of other types or one
* is a string and the other is a number, a typecheck
* error occurs. <p>
*
* errors: invalidaccess, stackunderflow, typecheck
*/
void eval() {
double num2 = popDouble();
double num1 = popDouble();
pushBoolean(num1 >= num2);
}
});
operationSet.add(new Operation("gt") {
/**
* <i>num1 num2</i> <b>gt</b> <i>bool</i> <p>
*
* pops two objects from the operand stack and pushes true
* if the first operand is greater than the second, or
* false otherwise. If both operands are numbers, gt compares
* their mathematical values. If both operands are strings,
* gt compares them element by element, treating the elements
* as integers in the range 0 to 255, to determine whether
* the first string is lexically greater than the second.
* If the operands are of other types or one is a string
* and the other is a number, a typecheck error occurs. <p>
*
* errors: invalidaccess, stackunderflow, typecheck
*/
void eval() {
double num2 = popDouble();
double num1 = popDouble();
pushBoolean(num1 > num2);
}
});
operationSet.add(new Operation("le") {
/**
* <i>num1 num2</i> <b>le</b> <i>bool</i> <p>
*
* pops two objects from the operand stack and pushes true
* if the first operand is less than or equal to the second,
* or false otherwise. If both operands are numbers, le
* compares their mathematical values. If both operands are
* strings, le compares them element by element, treating
* the elements as integers in the range 0 to 255,
* to determine whether the first string is lexically less
* than or equal to the second. If the operands are of other
* types or one is a string and the other is a number, a
* typecheck error occurs.<p>
*
* errors: invalidaccess, stackunderflow, typecheck
*/
void eval() {
double num2 = popDouble();
double num1 = popDouble();
pushBoolean(num1 <= num2);
}
});
operationSet.add(new Operation("lt") {
/**
* <i>num1 num2</i> <b>lt</b> <i>bool</i> <p>
*
* pops two objects from the operand stack and pushes true
* if the first operand is less than the second, or false
* otherwise. If both operands are numbers, lt compares
* their mathematical values. If both operands are strings,
* lt compares them element by element, treating the elements
* as integers in the range 0 to 255, to determine whether
* the first string is lexically less than the second.
* If the operands are of other types or one is a string
* and the other is a number, a typecheck error occurs. <p>
*
* errors: invalidaccess, stackunderflow, typecheck
*/
void eval() {
double num2 = popDouble();
double num1 = popDouble();
pushBoolean(num1 < num2);
}
});
operationSet.add(new Operation("ne") {
/**
* <i>any1 any2</i> <b>ne</b> <i>bool</i> <p>
*
* pops two objects from the operand stack and pushes false
* if they are equal, or true if not. What it means for objects
* to be equal is presented in the description of the
* eq operator. <p>
*
* errors: invalidaccess, stackunderflow
*/
void eval() {
pushBoolean(!popObject().equals(popObject()));
}
});
operationSet.add(new Operation("not") {
/**
* <i>bool1|int1</i> <b>not</b> <i>bool2|int2</i> <p>
*
* returns the logical negation of the operand if it is
* boolean. If the operand is an integer, not returns the
* bitwise complement (ones complement) of its binary
* representation. <p>
*
* errors: stackunderflow, typecheck
*/
void eval() {
pushLong(~popLong());
}
});
operationSet.add(new Operation("or") {
/**
* <i>bool1|int1 bool2|int2</i> <b>or</b> <i>bool3|int3</i> <p>
*
* returns the logical disjunction of the operands if they
* are boolean. If the operands are integers, or returns
* the bitwise "inclusive or" of their binary representations. <p>
*
* errors: stackunderflow, typecheck
*/
void eval() {
pushLong(popLong() | popLong());
}
});
operationSet.add(new Operation("true") {
/**
* <b>true</b> <i>true</i> <p>
*
* pushes a boolean object whose value is true on the operand
* stack. true is not an operator; it is a name in systemdict
* associated with the boolean value true. <p>
*
* errors: stackoverflow
*/
void eval() {
pushBoolean(true);
}
});
operationSet.add(new Operation("xor") {
/**
* <i>bool1|int1 bool2|int2</i> <b>xor</b> <i>bool3|int3</i> <p>
*
* returns the logical "exclusive or" of the operands if they
* are boolean. If the operands are integers, xor returns the
* bitwise "exclusive or" of their binary representations. <p>
*
* errors: stackunderflow, typecheck
*/
void eval() {
pushLong(popLong() ^ popLong());
}
});
// Conditional Operators
operationSet.add(new Operation("if") {
/**
* <i>bool {proc}</i> <b>if</b> - <p>
*
* removes both operands from the stack, then executes proc
* if bool is true. The if operator pushes no results of
* its own on the operand stack, but proc may do so (see
* Section 3.5, "Execution"). <p>
*
* Examples <p>
* 3 4 lt {(3 is less than 4)} if <p>
*
* errors: stackunderflow, typecheck
*/
void eval() {
if (popBoolean()) {
stack.addFirst(popExpression());
} else {
popExpression();
}
}
});
operationSet.add(new Operation("ifelse") {
/**
* <i>bool {expr1} {expr2}</i> <b>ifelse</b> - <p>
*
* removes all three operands from the stack, then
* executes proc1 if bool is true or proc2 if bool is false.
* The ifelse operator pushes no results of its own on the
* operand stack, but the procedure it executes may do so
* (see Section 3.5, "Execution"). <p>
*
* Examples <p>
* 4 3 lt {(TruePart)} {(FalsePart)} ifelse <br>
* results in FalsePart, since 4 is not less than 3 <p>
*
* errors: stackunderflow, typecheck
*/
void eval() {
// execute expr1 if bool is true, expr2 if false
if (popBoolean()) {
// expression.push(popExpression());
popExpression();
} else {
popExpression();
// expression.push(popExpression());
}
}
});
// Stack Operators
operationSet.add(new Operation("copy") {
/**
* <i>any1 ... anyn n</i> <b>copy</b> <i>any1 ... anyn any1 ... anyn</i>
* <i>array1 array2</i> <b>copy</b> <i>subarray2</i> <br>
* <i>string1 string2</i> <b>copy</b> <i>substring2</i> <p>
*
* performs two entirely different functions, depending on the
* type of the topmost operand.
* In the first form, where the top element on the operand
* stack is a nonnegative integer n, copy pops n from the
* stack and duplicates the top n elements on the stack
* as shown above. This form of copy operates only on the
* objects themselves, not on the values of composite objects. <p>
*
* Examples<br>
* (a) (b) (c) 2 copy Þ (a) (b) (c) (b) (c) <br>
* (a) (b) (c) 0 copy Þ (a) (b) (c) <p>
*
* In the other forms, copy copies all the elements of the
* first composite object into the second. The composite
* object operands must be of the same type, except that
* a packed array can be copied into an array (and only into
* an array—copy cannot copy into packed arrays, because
* they are read-only). This form of copy copies the value of
* a composite object. This is quite different from dup and
* other operators that copy only the objects themselves
* (see Section 3.3.1, "Simple and Composite Objects").
* However, copy performs only one level of copying.
* It does not apply recursively to elements that are
* themselves composite objects; instead, the values
* of those elements become shared. In the case of arrays or
* strings, the length of the second object must be at least as
* great as the first; copy returns the initial subarray or
* substring of the second operand into which the elements
* were copied. Any remaining elements of array2 or
* string2 are unaffected. <p>
*
* Example: <br>
* /a1 [1 2 3] def<br>
* a1 dup length array copy Þ [1 2 3] <p>
*
* errors: invalidaccess, rangecheck, stackoverflow,
* stackunderflow, typecheck
*/
void eval() {
long count = popLong();
// ????
Object obj = stack.removeFirst();
stack.addFirst(obj);
stack.addFirst(obj);
}
});
operationSet.add(new Operation("dup") {
/**
* <i>any</i> <b>dup</b> <i>any any</i> <p>
*
* duplicates the top element on the operand stack.
* dup copies only the object; the value of a composite
* object is not copied but is shared.
* See Section 3.3, "Data Types and Objects." <p>
*
* errors: stackoverflow, stackunderflow
*/
void eval() {
Object obj = popObject();
pushObject(obj);
pushObject(obj);
}
});
operationSet.add(new Operation("exch") {
void eval() { // <i>any1 any2</i> <b>exch</b> <i>any2 any1</i> - exchange top of stack
Object any1 = popObject();
Object any2 = popObject();
pushObject(any2);
pushObject(any1);
}
});
operationSet.add(new Operation("index") {
void eval() { // <i>anyn ... any0 n</i> <b>index</b> <i>anyn ... any0 anyn</i>
Object obj = stack.removeFirst();
stack.addFirst(obj);
stack.addFirst(obj);
}
});
operationSet.add(new Operation("pop") {
void eval() { // discard top element
stack.removeFirst();
}
});
operationSet.add(new Operation("roll") {
void eval() {
// <i>anyn-1 ... any0 n j</i> <b>roll</b> <i>any(j-1)mod n ... anyn-1 ... any</i>
// Roll n elements up j times
Object obj = stack.removeFirst();
stack.addFirst(obj);
stack.addFirst(obj);
}
});
}
}
/** Read the function information from a PDF Object */
protected void parse(PDFObject obj) throws IOException {
// read the postscript from the stream
readPS(obj.getStreamBuffer());
throw new PDFParseException("Unsupported function type 4.");
}
/**
* Map from <i>m</i> input values to <i>n</i> output values.
* The number of inputs <i>m</i> must be exactly one half the size of the
* domain. The number of outputs should match one half the size of the
* range.
*
* @param inputs an array of <i>m</i> input values
* @param outputs an array of size <i>n</i> which will be filled
* with the output values, or null to return a new array
*/
protected void doFunction(float[] inputs, int inputOffset,
float[] outputs, int outputOffset) {
}
private boolean popBoolean() {
return false;
}
private void pushBoolean(boolean arg) {
}
private double popDouble() {
return 0;
}
private void pushDouble(double arg) {
}
private Expression popExpression() {
return null;
}
private void pushExpression(Expression expresson) {
}
private long popLong() {
return 0L;
}
private void pushLong(long arg) {
}
private Object popObject() {
return stack.removeFirst();
}
private void pushObject(Object obj) {
stack.addFirst(obj);
}
/**
* <p>parse the postscript operators and aguments from the stream.</p>
*
* <p>Syntax is to read a set of tokens, including expressions and
* to queue them as they come including other expressions. Expressions are
* enclosed in curly brackets and constitute a reference to the
* expression body.</p>
*
* @param buf the stream of postscript tokens
*/
private void readPS(ByteBuffer buf) {
}
class Expression extends LinkedList {
public boolean equals(Object obj) {
if (obj instanceof Expression) {
// actually validate the list contents are the same expressions
return true;
}
return false;
}
}
abstract class Operation {
private String operatorName;
public Operation(String operatorName) {
if (operatorName == null) {
throw new RuntimeException("Cannot have a null operator name");
}
this.operatorName = operatorName;
}
public String getOperatorName() {
return operatorName;
}
/**
* evaluate the function, popping the stack as needed and pushing results.
*/
abstract void eval();
/**
* return true if our operator is the same as the supplied one.
*
* @param obj
* @return
*/
public boolean equals(Object obj) {
if (obj instanceof Operation) {
return ((Operation) obj).operatorName.equals(operatorName);
} else if (obj instanceof String) {
return operatorName.equals(obj);
}
return false;
}
}
}