001: /* ====================================================================
002: Licensed to the Apache Software Foundation (ASF) under one or more
003: contributor license agreements. See the NOTICE file distributed with
004: this work for additional information regarding copyright ownership.
005: The ASF licenses this file to You under the Apache License, Version 2.0
006: (the "License"); you may not use this file except in compliance with
007: the License. You may obtain a copy of the License at
008:
009: http://www.apache.org/licenses/LICENSE-2.0
010:
011: Unless required by applicable law or agreed to in writing, software
012: distributed under the License is distributed on an "AS IS" BASIS,
013: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: See the License for the specific language governing permissions and
015: limitations under the License.
016: ==================================================================== */
017:
018: package org.apache.poi.hssf.record.formula;
019:
020: import java.util.List;
021: import java.util.ArrayList;
022: import java.util.Stack;
023:
024: import org.apache.poi.hssf.model.Workbook;
025: import org.apache.poi.hssf.record.RecordInputStream;
026:
027: /**
028: *
029: * @author andy
030: * @author avik
031: * @author Jason Height (jheight at chariot dot net dot au)
032: */
033:
034: public abstract class Ptg {
035:
036: /* convert infix order ptg list to rpn order ptg list
037: * @return List ptgs in RPN order
038: * @param infixPtgs List of ptgs in infix order
039: */
040:
041: /* DO NOT REMOVE
042: *we keep this method in case we wish to change the way we parse
043: *It needs a getPrecedence in OperationsPtg
044:
045: public static List ptgsToRpn(List infixPtgs) {
046: java.util.Stack operands = new java.util.Stack();
047: java.util.List retval = new java.util.Stack();
048:
049: java.util.ListIterator i = infixPtgs.listIterator();
050: Object p;
051: OperationPtg o ;
052: boolean weHaveABracket = false;
053: while (i.hasNext()) {
054: p=i.next();
055: if (p instanceof OperationPtg) {
056: if (p instanceof ParenthesisPtg) {
057: if (!weHaveABracket) {
058: operands.push(p);
059: weHaveABracket = true;
060: } else {
061: o = (OperationPtg) operands.pop();
062: while (!(o instanceof ParenthesisPtg)) {
063: retval.add(o);
064: }
065: weHaveABracket = false;
066: }
067: } else {
068:
069: while (!operands.isEmpty() && ((OperationPtg) operands.peek()).getPrecedence() >= ((OperationPtg) p).getPrecedence() ) { //TODO handle ^ since it is right associative
070: retval.add(operands.pop());
071: }
072: operands.push(p);
073: }
074: } else {
075: retval.add(p);
076: }
077: }
078: while (!operands.isEmpty()) {
079: if (operands.peek() instanceof ParenthesisPtg ){
080: //throw some error
081: } else {
082: retval.add(operands.pop());
083: }
084: }
085: return retval;
086: }
087: */
088:
089: public static Stack createParsedExpressionTokens(short size,
090: RecordInputStream in) {
091: Stack stack = new Stack();
092: int pos = 0;
093: List arrayPtgs = null;
094: while (pos < size) {
095: Ptg ptg = Ptg.createPtg(in);
096: if (ptg instanceof ArrayPtg) {
097: if (arrayPtgs == null)
098: arrayPtgs = new ArrayList(5);
099: arrayPtgs.add(ptg);
100: pos += 8;
101: } else
102: pos += ptg.getSize();
103: stack.push(ptg);
104: }
105: if (arrayPtgs != null) {
106: for (int i = 0; i < arrayPtgs.size(); i++) {
107: ArrayPtg p = (ArrayPtg) arrayPtgs.get(i);
108: p.readTokenValues(in);
109: }
110: }
111: return stack;
112: }
113:
114: public static Ptg createPtg(RecordInputStream in) {
115: byte id = in.readByte();
116: Ptg retval = null;
117:
118: switch (id) {
119: case ExpPtg.sid: // 0x01
120: retval = new ExpPtg(in);
121: break;
122:
123: case AddPtg.sid: // 0x03
124: retval = new AddPtg(in);
125: break;
126:
127: case SubtractPtg.sid: // 0x04
128: retval = new SubtractPtg(in);
129: break;
130:
131: case MultiplyPtg.sid: // 0x05
132: retval = new MultiplyPtg(in);
133: break;
134:
135: case DividePtg.sid: // 0x06
136: retval = new DividePtg(in);
137: break;
138:
139: case PowerPtg.sid: // 0x07
140: retval = new PowerPtg(in);
141: break;
142:
143: case ConcatPtg.sid: // 0x08
144: retval = new ConcatPtg(in);
145: break;
146:
147: case LessThanPtg.sid: // 0x09
148: retval = new LessThanPtg(in);
149: break;
150:
151: case LessEqualPtg.sid: // 0x0a
152: retval = new LessEqualPtg(in);
153: break;
154:
155: case EqualPtg.sid: // 0x0b
156: retval = new EqualPtg(in);
157: break;
158:
159: case GreaterEqualPtg.sid: // 0x0c
160: retval = new GreaterEqualPtg(in);
161: break;
162:
163: case GreaterThanPtg.sid: // 0x0d
164: retval = new GreaterThanPtg(in);
165: break;
166:
167: case NotEqualPtg.sid: // 0x0e
168: retval = new NotEqualPtg(in);
169: break;
170:
171: case IntersectionPtg.sid: // 0x0f
172: retval = new IntersectionPtg(in);
173: break;
174: case UnionPtg.sid: // 0x10
175: retval = new UnionPtg(in);
176: break;
177:
178: case RangePtg.sid: // 0x11
179: retval = new RangePtg(in);
180: break;
181:
182: case UnaryPlusPtg.sid: // 0x12
183: retval = new UnaryPlusPtg(in);
184: break;
185:
186: case UnaryMinusPtg.sid: // 0x13
187: retval = new UnaryMinusPtg(in);
188: break;
189:
190: case PercentPtg.sid: // 0x14
191: retval = new PercentPtg(in);
192: break;
193:
194: case ParenthesisPtg.sid: // 0x15
195: retval = new ParenthesisPtg(in);
196: break;
197:
198: case MissingArgPtg.sid: // 0x16
199: retval = new MissingArgPtg(in);
200: break;
201:
202: case StringPtg.sid: // 0x17
203: retval = new StringPtg(in);
204: break;
205:
206: case AttrPtg.sid: // 0x19
207: retval = new AttrPtg(in);
208: break;
209:
210: case ErrPtg.sid: // 0x1c
211: retval = new ErrPtg(in);
212: break;
213:
214: case BoolPtg.sid: // 0x1d
215: retval = new BoolPtg(in);
216: break;
217:
218: case IntPtg.sid: // 0x1e
219: retval = new IntPtg(in);
220: break;
221:
222: case NumberPtg.sid: // 0x1f
223: retval = new NumberPtg(in);
224: break;
225:
226: case ArrayPtg.sid: // 0x20
227: retval = new ArrayPtg(in);
228: break;
229: case ArrayPtgV.sid: // 0x40
230: retval = new ArrayPtgV(in);
231: break;
232: case ArrayPtgA.sid: // 0x60
233: retval = new ArrayPtgA(in);
234: break;
235:
236: case FuncPtg.sid: // 0x21
237: case FuncPtg.sid + 0x20: // 0x41
238: case FuncPtg.sid + 0x40: // 0x61
239: retval = new FuncPtg(in);
240: break;
241:
242: case FuncVarPtg.sid: // 0x22
243: case FuncVarPtg.sid + 0x20: // 0x42
244: case FuncVarPtg.sid + 0x40: // 0x62
245: retval = new FuncVarPtg(in);
246: break;
247:
248: case ReferencePtg.sid: // 0x24
249: retval = new ReferencePtg(in);
250: break;
251: case RefAPtg.sid: // 0x64
252: retval = new RefAPtg(in);
253: break;
254: case RefVPtg.sid: // 0x44
255: retval = new RefVPtg(in);
256: break;
257: case RefNAPtg.sid: // 0x6C
258: retval = new RefNAPtg(in);
259: break;
260: case RefNPtg.sid: // 0x2C
261: retval = new RefNPtg(in);
262: break;
263: case RefNVPtg.sid: // 0x4C
264: retval = new RefNVPtg(in);
265: break;
266:
267: case AreaPtg.sid: // 0x25
268: retval = new AreaPtg(in);
269: break;
270: case AreaVPtg.sid: // 0x45
271: retval = new AreaVPtg(in);
272: break;
273: case AreaAPtg.sid: // 0x65
274: retval = new AreaAPtg(in);
275: break;
276: case AreaNAPtg.sid: // 0x6D
277: retval = new AreaNAPtg(in);
278: break;
279: case AreaNPtg.sid: // 0x2D
280: retval = new AreaNPtg(in);
281: break;
282: case AreaNVPtg.sid: // 0x4D
283: retval = new AreaNVPtg(in);
284: break;
285:
286: case MemAreaPtg.sid: // 0x26
287: case MemAreaPtg.sid + 0x40: // 0x46
288: case MemAreaPtg.sid + 0x20: // 0x66
289: retval = new MemAreaPtg(in);
290: break;
291:
292: case MemErrPtg.sid: // 0x27
293: case MemErrPtg.sid + 0x20: // 0x47
294: case MemErrPtg.sid + 0x40: // 0x67
295: retval = new MemErrPtg(in);
296: break;
297:
298: case MemFuncPtg.sid: // 0x29
299: retval = new MemFuncPtg(in);
300: break;
301:
302: case RefErrorPtg.sid: // 0x2a
303: case RefErrorPtg.sid + 0x20: // 0x4a
304: case RefErrorPtg.sid + 0x40: // 0x6a
305: retval = new RefErrorPtg(in);
306: break;
307:
308: case AreaErrPtg.sid: // 0x2b
309: case AreaErrPtg.sid + 0x20: // 0x4b
310: case AreaErrPtg.sid + 0x40: // 0x6b
311: retval = new AreaErrPtg(in);
312: break;
313:
314: case NamePtg.sid: // 0x23
315: case NamePtg.sid + 0x20: // 0x43
316: case NamePtg.sid + 0x40: // 0x63
317: retval = new NamePtg(in);
318: break;
319:
320: case NameXPtg.sid: // 0x39
321: case NameXPtg.sid + 0x20: // 0x45
322: case NameXPtg.sid + 0x40: // 0x79
323: retval = new NameXPtg(in);
324: break;
325:
326: case Area3DPtg.sid: // 0x3b
327: case Area3DPtg.sid + 0x20: // 0x5b
328: case Area3DPtg.sid + 0x40: // 0x7b
329: retval = new Area3DPtg(in);
330: break;
331:
332: case Ref3DPtg.sid: // 0x3a
333: case Ref3DPtg.sid + 0x20: // 0x5a
334: case Ref3DPtg.sid + 0x40: // 0x7a
335: retval = new Ref3DPtg(in);
336: break;
337:
338: case DeletedRef3DPtg.sid: // 0x3c
339: case DeletedRef3DPtg.sid + 0x20: // 0x5c
340: case DeletedRef3DPtg.sid + 0x40: // 0x7c
341: retval = new DeletedRef3DPtg(in);
342: break;
343:
344: case DeletedArea3DPtg.sid: // 0x3d
345: case DeletedArea3DPtg.sid + 0x20: // 0x5d
346: case DeletedArea3DPtg.sid + 0x40: // 0x7d
347: retval = new DeletedArea3DPtg(in);
348: break;
349:
350: default:
351:
352: //retval = new UnknownPtg();
353: throw new java.lang.UnsupportedOperationException(
354: " Unknown Ptg in Formula: 0x"
355: + Integer.toHexString((int) id) + " ("
356: + (int) id + ")");
357: }
358:
359: if (id > 0x60) {
360: retval.setClass(CLASS_ARRAY);
361: } else if (id > 0x40) {
362: retval.setClass(CLASS_VALUE);
363: } else {
364: retval.setClass(CLASS_REF);
365: }
366:
367: return retval;
368:
369: }
370:
371: public static int serializePtgStack(Stack expression, byte[] array,
372: int offset) {
373: int pos = 0;
374: int size = 0;
375: if (expression != null)
376: size = expression.size();
377:
378: List arrayPtgs = null;
379:
380: for (int k = 0; k < size; k++) {
381: Ptg ptg = (Ptg) expression.get(k);
382:
383: ptg.writeBytes(array, pos + offset);
384: if (ptg instanceof ArrayPtg) {
385: if (arrayPtgs == null)
386: arrayPtgs = new ArrayList(5);
387: arrayPtgs.add(ptg);
388: pos += 8;
389: } else
390: pos += ptg.getSize();
391: }
392: if (arrayPtgs != null) {
393: for (int i = 0; i < arrayPtgs.size(); i++) {
394: ArrayPtg p = (ArrayPtg) arrayPtgs.get(i);
395: pos += p.writeTokenValueBytes(array, pos + offset);
396: }
397: }
398: return pos;
399: }
400:
401: public abstract int getSize();
402:
403: public final byte[] getBytes() {
404: int size = getSize();
405: byte[] bytes = new byte[size];
406:
407: writeBytes(bytes, 0);
408: return bytes;
409: }
410:
411: /** write this Ptg to a byte array*/
412: public abstract void writeBytes(byte[] array, int offset);
413:
414: /**
415: * return a string representation of this token alone
416: */
417: public abstract String toFormulaString(Workbook book);
418:
419: /**
420: * dump a debug representation (hexdump) to a string
421: */
422: public String toDebugString() {
423: byte[] ba = new byte[getSize()];
424: String retval = null;
425: writeBytes(ba, 0);
426: try {
427: retval = org.apache.poi.util.HexDump.dump(ba, 0, 0);
428: } catch (Exception e) {
429: e.printStackTrace();
430: }
431: return retval;
432: }
433:
434: /** Overridden toString method to ensure object hash is not printed.
435: * This helps get rid of gratuitous diffs when comparing two dumps
436: * Subclasses may output more relevant information by overriding this method
437: **/
438: public String toString() {
439: return this .getClass().toString();
440: }
441:
442: public static final byte CLASS_REF = 0x00;
443: public static final byte CLASS_VALUE = 0x20;
444: public static final byte CLASS_ARRAY = 0x40;
445:
446: protected byte ptgClass = CLASS_REF; //base ptg
447:
448: public void setClass(byte thePtgClass) {
449: ptgClass = thePtgClass;
450: }
451:
452: /** returns the class (REF/VALUE/ARRAY) for this Ptg */
453: public byte getPtgClass() {
454: return ptgClass;
455: }
456:
457: public abstract byte getDefaultOperandClass();
458:
459: public abstract Object clone();
460:
461: }
|