001/* 002 * Copyright (c) 2005 Einar Pehrson <einar@pehrson.nu>. 003 * 004 * This file is part of 005 * CleanSheets - a spreadsheet application for the Java platform. 006 * 007 * CleanSheets is free software; you can redistribute it and/or modify 008 * it under the terms of the GNU General Public License as published by 009 * the Free Software Foundation; either version 2 of the License, or 010 * (at your option) any later version. 011 * 012 * CleanSheets is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 015 * GNU General Public License for more details. 016 * 017 * You should have received a copy of the GNU General Public License 018 * along with CleanSheets; if not, write to the Free Software 019 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 020 */ 021package csheets.core.formula.compiler; 022 023import java.io.StringReader; 024import java.text.ParseException; 025import java.util.*; 026 027import antlr.ANTLRException; 028import antlr.collections.AST; 029import csheets.core.*; 030import csheets.core.formula.*; 031import csheets.core.formula.lang.*; 032 033/** 034 * A compiler that generates '#'-style formulas from strings. (adapted from 035 * Einar Pehrson class, ExcelExpressionCompiler; changes are indicated below) 036 * 037 * @author João Carreira 038 * @see cshhets.core.formula.compiler.ExcelExpressionCompiler 039 */ 040public class NumberSignExpressionCompiler implements ExpressionCompiler { 041 042 /** The character that signals that a cell's content is a formula ('#') */ 043 /* changed from = to # */ 044 public static final char FORMULA_STARTER = '#'; 045 046 /** 047 * Creates the Excel expression compiler. 048 */ 049 public NumberSignExpressionCompiler() { 050 } 051 052 @Override 053 public char getStarter() { 054 return FORMULA_STARTER; 055 } 056 057 @Override 058 public Expression compile(Cell cell, String source) 059 throws FormulaCompilationException { 060 // Creates the lexer and parser 061 /* adapted to support the new parser and lexer */ 062 NumberSignFormulaParser parser = new NumberSignFormulaParser( 063 new NumberSignFormulaLexer(new StringReader(source))); 064 try { 065 // Attempts to match an expression 066 parser.expression(); 067 } catch (ANTLRException e) { 068 throw new FormulaCompilationException(e); 069 } 070 // Converts the expression and returns it 071 return convert(cell, parser.getAST()); 072 } 073 074 /** 075 * Converts the given ANTLR AST to an expression. 076 * 077 * @param node 078 * the abstract syntax tree node to convert 079 * @return the result of the conversion 080 */ 081 protected Expression convert(Cell cell, AST node) 082 throws FormulaCompilationException { 083 // System.out.println("Converting node '" + node.getText() + 084 // "' of tree '" + node.toStringTree() + "' with " + 085 // node.getNumberOfChildren() + " children."); 086 if (node.getNumberOfChildren() == 0) { 087 try { 088 switch (node.getType()) { 089 case NumberSignFormulaParserTokenTypes.NUMBER: 090 return new Literal(Value.parseNumericValue(node.getText())); 091 case NumberSignFormulaParserTokenTypes.STRING: 092 return new Literal(Value.parseValue(node.getText(), 093 Value.Type.BOOLEAN, Value.Type.DATE)); 094 case NumberSignFormulaParserTokenTypes.CELL_REF: 095 return new CellReference(cell.getSpreadsheet(), 096 node.getText()); 097 case NumberSignFormulaParserTokenTypes.NAME: 098 /* 099 * return cell.getSpreadsheet().getWorkbook(). 100 * getRange(node.getText()) (Reference) 101 */ 102 } 103 } catch (ParseException e) { 104 throw new FormulaCompilationException(e); 105 } 106 } 107 108 // Convert function call 109 Function function = null; 110 try { 111 function = Language.getInstance().getFunction(node.getText()); 112 } catch (UnknownElementException e) { 113 } 114 115 if (function != null) { 116 List<Expression> args = new ArrayList<Expression>(); 117 AST child = node.getFirstChild(); 118 if (function instanceof Eval) { 119 120 try { 121 122 Expression expression = convert(cell, node.getFirstChild()); 123 cell.setContent(expression.evaluate().toText()); 124 } catch (IllegalValueTypeException e) { 125 } 126 127 } 128 if (child != null) { 129 args.add(convert(cell, child)); 130 while ((child = child.getNextSibling()) != null) 131 args.add(convert(cell, child)); 132 } 133 134 Expression[] argArray = args.toArray(new Expression[args.size()]); 135 136 if (function instanceof Whiledo) { 137 138 try { 139 while (argArray[0].evaluate().toBoolean()) { 140 convert(cell, node); 141 } 142 } catch (IllegalValueTypeException e) { 143 } 144 } 145 if (function instanceof Dowhile) { 146 147 try { 148 while (argArray[argArray.length - 1].evaluate().toBoolean()) { 149 convert(cell, node); 150 } 151 } catch (IllegalValueTypeException e) { 152 } 153 } 154 return new FunctionCall(function, argArray); 155 } 156 157 if (node.getNumberOfChildren() == 1) 158 // Convert unary operation 159 return new UnaryOperation(Language.getInstance().getUnaryOperator( 160 node.getText()), convert(cell, node.getFirstChild())); 161 else if (node.getNumberOfChildren() >= 2) { 162 // Convert binary operation 163 if (node.getType() == NumberSignFormulaParserTokenTypes.SEMI) { 164 convert(cell, node.getFirstChild()); 165 return convert(cell, node.getFirstChild().getNextSibling()); 166 } else { 167 BinaryOperator operator = Language.getInstance() 168 .getBinaryOperator(node.getText()); 169 if (operator instanceof RangeReference) { 170 171 return new ReferenceOperation((Reference) convert(cell, 172 node.getFirstChild()), (RangeReference) operator, 173 (Reference) convert(cell, node.getFirstChild() 174 .getNextSibling())); 175 } else if (operator instanceof RelationalOperatorImpl) { 176 return new RelationalOperatorImpl((Reference) convert(cell, 177 node.getFirstChild()), (RangeReference) operator, 178 (Reference) convert(cell, node.getFirstChild() 179 .getNextSibling())); 180 } 181 /* verifies is operator is ':=' */ 182 else if (operator instanceof Attribution) { 183 try { 184 CellReference cellRef = new CellReference( 185 cell.getSpreadsheet(), node.getFirstChild() 186 .getText()); 187 Cell destinationCell = cellRef.getCell(); 188 AST next = node.getFirstChild(); 189 Expression exp = convert(destinationCell, 190 next.getNextSibling()); 191 Value val = exp.evaluate(); 192 UpdateCellContent.getInstance().triggerUpdate( 193 destinationCell, val); 194 } catch (ParseException e) { 195 throw new FormulaCompilationException(e); 196 } catch (IllegalValueTypeException e) { 197 throw new FormulaCompilationException(e); 198 } 199 return new BinaryOperation(convert(cell, 200 node.getFirstChild()), operator, convert(cell, node 201 .getFirstChild().getNextSibling())); 202 } else { 203 return new BinaryOperation(convert(cell, 204 node.getFirstChild()), operator, convert(cell, node 205 .getFirstChild().getNextSibling())); 206 } 207 } 208 } else { 209 // Shouldn't happen 210 throw new FormulaCompilationException(); 211 } 212 } 213}