KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jxl > biff > formula > TokenFormulaParser


1 /*********************************************************************
2 *
3 * Copyright (C) 2002 Andrew Khan
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 ***************************************************************************/

19
20 package jxl.biff.formula;
21
22 import java.util.Stack JavaDoc;
23
24 import common.Assert;
25 import common.Logger;
26
27 import jxl.Cell;
28 import jxl.WorkbookSettings;
29 import jxl.biff.WorkbookMethods;
30
31 /**
32  * Parses the excel ptgs into a parse tree
33  */

34 class TokenFormulaParser implements Parser
35 {
36   /**
37    * The logger
38    */

39   private static Logger logger = Logger.getLogger(TokenFormulaParser.class);
40
41   /**
42    * The Excel ptgs
43    */

44   private byte[] tokenData;
45
46   /**
47    * The cell containing the formula. This is used in order to determine
48    * relative cell values
49    */

50   private Cell relativeTo;
51
52   /**
53    * The current position within the array
54    */

55   private int pos;
56
57   /**
58    * The parse tree
59    */

60   private ParseItem root;
61
62   /**
63    * The hash table of items that have been parsed
64    */

65   private Stack JavaDoc tokenStack;
66
67   /**
68    * A reference to the workbook which holds the external sheet
69    * information
70    */

71   private ExternalSheet workbook;
72
73   /**
74    * A reference to the name table
75    */

76   private WorkbookMethods nameTable;
77
78   /**
79    * The workbook settings
80    */

81   private WorkbookSettings settings;
82
83   /**
84    * Constructor
85    */

86   public TokenFormulaParser(byte[] data, Cell c, ExternalSheet es,
87                             WorkbookMethods nt,
88                             WorkbookSettings ws)
89   {
90     tokenData = data;
91     pos = 0;
92     relativeTo = c;
93     workbook = es;
94     nameTable = nt;
95     tokenStack = new Stack JavaDoc();
96     settings = ws;
97   }
98
99   /**
100    * Parses the sublist of tokens. In most cases this will equate to
101    * the full list
102    *
103    * @exception FormulaException
104    */

105   public void parse() throws FormulaException
106   {
107     parseSubExpression(tokenData.length);
108
109     // Finally, there should be one thing left on the stack. Get that
110
// and add it to the root node
111
root = (ParseItem) tokenStack.pop();
112
113     Assert.verify(tokenStack.empty());
114
115   }
116
117   /**
118    * Parses the sublist of tokens. In most cases this will equate to
119    * the full list
120    *
121    * @param len the length of the subexpression to parse
122    * @exception FormulaException
123    */

124   private void parseSubExpression(int len) throws FormulaException
125   {
126     int tokenVal = 0;
127     Token t = null;
128     
129     // Indicates that we are parsing the incredibly complicated and
130
// hacky if construct that MS saw fit to include, the gits
131
Stack JavaDoc ifStack = new Stack JavaDoc();
132
133     // The end position of the sub-expression
134
int endpos = pos + len;
135
136     while (pos < endpos)
137     {
138       tokenVal = tokenData[pos];
139       pos++;
140
141       t = Token.getToken(tokenVal);
142
143       if (t == Token.UNKNOWN)
144       {
145         throw new FormulaException
146           (FormulaException.unrecognizedToken, tokenVal);
147       }
148
149       Assert.verify(t != Token.UNKNOWN);
150
151       // Operands
152
if (t == Token.REF)
153       {
154         CellReference cr = new CellReference(relativeTo);
155         pos += cr.read(tokenData, pos);
156         tokenStack.push(cr);
157       }
158       else if (t == Token.REFV)
159       {
160         SharedFormulaCellReference cr =
161           new SharedFormulaCellReference(relativeTo);
162         pos += cr.read(tokenData, pos);
163         tokenStack.push(cr);
164       }
165       else if (t == Token.REF3D)
166       {
167         CellReference3d cr = new CellReference3d(relativeTo, workbook);
168         pos += cr.read(tokenData, pos);
169         tokenStack.push(cr);
170       }
171       else if (t == Token.AREA)
172       {
173         Area a = new Area();
174         pos += a.read(tokenData, pos);
175         tokenStack.push(a);
176       }
177       else if (t == Token.AREAV)
178       {
179         SharedFormulaArea a = new SharedFormulaArea(relativeTo);
180         pos += a.read(tokenData, pos);
181         tokenStack.push(a);
182       }
183       else if (t == Token.AREA3D)
184       {
185         Area3d a = new Area3d(workbook);
186         pos += a.read(tokenData, pos);
187         tokenStack.push(a);
188       }
189       else if (t == Token.NAME)
190       {
191         Name n = new Name();
192         pos += n.read(tokenData, pos);
193         tokenStack.push(n);
194       }
195       else if (t == Token.NAMED_RANGE)
196       {
197         NameRange nr = new NameRange(nameTable);
198         pos += nr.read(tokenData, pos);
199         tokenStack.push(nr);
200       }
201       else if (t == Token.INTEGER)
202       {
203         IntegerValue i = new IntegerValue();
204         pos += i.read(tokenData, pos);
205         tokenStack.push(i);
206       }
207       else if (t == Token.DOUBLE)
208       {
209         DoubleValue d = new DoubleValue();
210         pos += d.read(tokenData, pos);
211         tokenStack.push(d);
212       }
213       else if (t == Token.BOOL)
214       {
215         BooleanValue bv = new BooleanValue();
216         pos += bv.read(tokenData, pos);
217         tokenStack.push(bv);
218       }
219       else if (t == Token.STRING)
220       {
221         StringValue sv = new StringValue(settings);
222         pos += sv.read(tokenData, pos);
223         tokenStack.push(sv);
224       }
225       else if (t == Token.MISSING_ARG)
226       {
227         MissingArg ma = new MissingArg();
228         pos += ma.read(tokenData, pos);
229         tokenStack.push(ma);
230       }
231
232       // Unary Operators
233
else if (t == Token.UNARY_PLUS)
234       {
235         UnaryPlus up = new UnaryPlus();
236         pos += up.read(tokenData, pos);
237         addOperator(up);
238       }
239       else if (t == Token.UNARY_MINUS)
240       {
241         UnaryMinus um = new UnaryMinus();
242         pos += um.read(tokenData, pos);
243         addOperator(um);
244       }
245       else if (t == Token.PERCENT)
246       {
247         Percent p = new Percent();
248         pos += p.read(tokenData, pos);
249         addOperator(p);
250       }
251
252       // Binary Operators
253
else if (t == Token.SUBTRACT)
254       {
255         Subtract s = new Subtract();
256         pos += s.read(tokenData, pos);
257         addOperator(s);
258       }
259       else if (t == Token.ADD)
260       {
261         Add s = new Add();
262         pos += s.read(tokenData, pos);
263         addOperator(s);
264       }
265       else if (t == Token.MULTIPLY)
266       {
267         Multiply s = new Multiply();
268         pos += s.read(tokenData, pos);
269         addOperator(s);
270       }
271       else if (t == Token.DIVIDE)
272       {
273         Divide s = new Divide();
274         pos += s.read(tokenData, pos);
275         addOperator(s);
276       }
277       else if (t == Token.CONCAT)
278       {
279         Concatenate c = new Concatenate();
280         pos += c.read(tokenData, pos);
281         addOperator(c);
282       }
283       else if (t == Token.POWER)
284       {
285         Power p = new Power();
286         pos += p.read(tokenData, pos);
287         addOperator(p);
288       }
289       else if (t == Token.LESS_THAN)
290       {
291         LessThan lt = new LessThan();
292         pos += lt.read(tokenData, pos);
293         addOperator(lt);
294       }
295       else if (t == Token.LESS_EQUAL)
296       {
297         LessEqual lte = new LessEqual();
298         pos += lte.read(tokenData, pos);
299         addOperator(lte);
300       }
301       else if (t == Token.GREATER_THAN)
302       {
303         GreaterThan gt = new GreaterThan();
304         pos += gt.read(tokenData, pos);
305         addOperator(gt);
306       }
307       else if (t == Token.GREATER_EQUAL)
308       {
309         GreaterEqual gte = new GreaterEqual();
310         pos += gte.read(tokenData, pos);
311         addOperator(gte);
312       }
313       else if (t == Token.NOT_EQUAL)
314       {
315         NotEqual ne = new NotEqual();
316         pos += ne.read(tokenData, pos);
317         addOperator(ne);
318       }
319       else if (t == Token.EQUAL)
320       {
321         Equal e = new Equal();
322         pos += e.read(tokenData, pos);
323         addOperator(e);
324       }
325       else if (t == Token.PARENTHESIS)
326       {
327         Parenthesis p = new Parenthesis();
328         pos += p.read(tokenData, pos);
329         addOperator(p);
330       }
331
332       // Functions
333
else if (t == Token.ATTRIBUTE)
334       {
335         Attribute a = new Attribute(settings);
336         pos += a.read(tokenData, pos);
337
338         if (a.isSum())
339         {
340           addOperator(a);
341         }
342         else if (a.isIf())
343         {
344           // Add it to a special stack for ifs
345
ifStack.push(a);
346         }
347       }
348       else if (t == Token.FUNCTION)
349       {
350         BuiltInFunction bif = new BuiltInFunction(settings);
351         pos += bif.read(tokenData, pos);
352
353         addOperator(bif);
354       }
355       else if (t == Token.FUNCTIONVARARG)
356       {
357         VariableArgFunction vaf = new VariableArgFunction(settings);
358         pos += vaf.read(tokenData, pos);
359
360         if (vaf.getFunction() != Function.ATTRIBUTE)
361         {
362           addOperator(vaf);
363         }
364         else
365         {
366           // This is part of an IF function. Get the operands, but then
367
// add it to the top of the if stack
368
vaf.getOperands(tokenStack);
369
370           Attribute ifattr = null;
371           if (ifStack.empty())
372           {
373             ifattr = new Attribute(settings);
374           }
375           else
376           {
377             ifattr = (Attribute) ifStack.pop();
378           }
379           
380           ifattr.setIfConditions(vaf);
381           tokenStack.push(ifattr);
382         }
383       }
384
385       // Other things
386
else if (t == Token.MEM_FUNC)
387       {
388         MemFunc memFunc = new MemFunc();
389         pos += memFunc.read(tokenData, pos);
390
391         // Create new tokenStack for the sub expression
392
Stack JavaDoc oldStack = tokenStack;
393         tokenStack = new Stack JavaDoc();
394
395         parseSubExpression(memFunc.getLength());
396
397         ParseItem[] subexpr = new ParseItem[tokenStack.size()];
398         int i = 0;
399         while (!tokenStack.isEmpty())
400         {
401           subexpr[i] = (ParseItem) tokenStack.pop();
402           i++;
403         }
404
405         memFunc.setSubExpression(subexpr);
406         
407         tokenStack = oldStack;
408         tokenStack.push(memFunc);
409       }
410     }
411   }
412
413   /**
414    * Adds the specified operator to the parse tree, taking operands off
415    * the stack as appropriate
416    */

417   private void addOperator(Operator o)
418   {
419     // Get the operands off the stack
420
o.getOperands(tokenStack);
421
422     // Add this operator onto the stack
423
tokenStack.push(o);
424   }
425
426   /**
427    * Gets the formula as a string
428    */

429   public String JavaDoc getFormula()
430   {
431     StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
432     root.getString(sb);
433     return sb.toString();
434   }
435
436   /**
437    * Adjusts all the relative cell references in this formula by the
438    * amount specified. Used when copying formulas
439    *
440    * @param colAdjust the amount to add on to each relative cell reference
441    * @param rowAdjust the amount to add on to each relative row reference
442    */

443   public void adjustRelativeCellReferences(int colAdjust, int rowAdjust)
444   {
445     root.adjustRelativeCellReferences(colAdjust, rowAdjust);
446   }
447
448   /**
449    * Gets the bytes for the formula. This takes into account any
450    * token mapping necessary because of shared formulas
451    *
452    * @return the bytes in RPN
453    */

454   public byte[] getBytes()
455   {
456     return root.getBytes();
457   }
458
459   /**
460    * Called when a column is inserted on the specified sheet. Tells
461    * the formula parser to update all of its cell references beyond this
462    * column
463    *
464    * @param sheetIndex the sheet on which the column was inserted
465    * @param col the column number which was inserted
466    * @param currentSheet TRUE if this formula is on the sheet in which the
467    * column was inserted, FALSE otherwise
468    */

469   public void columnInserted(int sheetIndex, int col, boolean currentSheet)
470   {
471     root.columnInserted(sheetIndex, col, currentSheet);
472   }
473   /**
474    * Called when a column is inserted on the specified sheet. Tells
475    * the formula parser to update all of its cell references beyond this
476    * column
477    *
478    * @param sheetIndex the sheet on which the column was removed
479    * @param col the column number which was removed
480    * @param currentSheet TRUE if this formula is on the sheet in which the
481    * column was inserted, FALSE otherwise
482    */

483   public void columnRemoved(int sheetIndex, int col, boolean currentSheet)
484   {
485     root.columnRemoved(sheetIndex, col, currentSheet);
486   }
487
488   /**
489    * Called when a column is inserted on the specified sheet. Tells
490    * the formula parser to update all of its cell references beyond this
491    * column
492    *
493    * @param sheetIndex the sheet on which the column was inserted
494    * @param row the column number which was inserted
495    * @param currentSheet TRUE if this formula is on the sheet in which the
496    * column was inserted, FALSE otherwise
497    */

498   public void rowInserted(int sheetIndex, int row, boolean currentSheet)
499   {
500     root.rowInserted(sheetIndex, row, currentSheet);
501   }
502
503   /**
504    * Called when a column is inserted on the specified sheet. Tells
505    * the formula parser to update all of its cell references beyond this
506    * column
507    *
508    * @param sheetIndex the sheet on which the column was removed
509    * @param row the column number which was removed
510    * @param currentSheet TRUE if this formula is on the sheet in which the
511    * column was inserted, FALSE otherwise
512    */

513   public void rowRemoved(int sheetIndex, int row, boolean currentSheet)
514   {
515     root.rowRemoved(sheetIndex, row, currentSheet);
516   }
517 }
518
519
520
521
522
523
524
525
526
527
Popular Tags