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 Excel-style formulas from strings. 035 * 036 * @author Einar Pehrson 037 */ 038public class ExcelExpressionCompiler implements ExpressionCompiler { 039 040 /** The character that signals that a cell's content is a formula ('=') */ 041 public static final char FORMULA_STARTER = '='; 042 043 /** 044 * Creates the Excel expression compiler. 045 */ 046 public ExcelExpressionCompiler() { 047 } 048 049 @Override 050 public char getStarter() { 051 return FORMULA_STARTER; 052 } 053 054 @Override 055 public Expression compile(Cell cell, String source) 056 throws FormulaCompilationException { 057 // Creates the lexer and parser 058 FormulaParser parser = new FormulaParser(new FormulaLexer( 059 new StringReader(source))); 060 061 try { 062 // Attempts to match an expression 063 parser.expression(); 064 } catch (ANTLRException e) { 065 throw new FormulaCompilationException(e); 066 } 067 068 // Converts the expression and returns it 069 return convert(cell, parser.getAST()); 070 } 071 072 /** 073 * Converts the given ANTLR AST to an expression. 074 * 075 * @param node 076 * the abstract syntax tree node to convert 077 * @return the result of the conversion 078 */ 079 protected Expression convert(Cell cell, AST node) 080 throws FormulaCompilationException { 081 // System.out.println("Converting node '" + node.getText() + 082 // "' of tree '" + node.toStringTree() + "' with " + 083 // node.getNumberOfChildren() + " children."); 084 if (node.getNumberOfChildren() == 0) { 085 try { 086 switch (node.getType()) { 087 case FormulaParserTokenTypes.NUMBER: 088 return new Literal(Value.parseNumericValue(node.getText())); 089 case FormulaParserTokenTypes.STRING: 090 return new Literal(Value.parseValue(node.getText(), 091 Value.Type.BOOLEAN, Value.Type.DATE)); 092 case FormulaParserTokenTypes.CELL_REF: 093 return new CellReference(cell.getSpreadsheet(), 094 node.getText()); 095 case FormulaParserTokenTypes.NAME: 096 /* 097 * return cell.getSpreadsheet().getWorkbook(). 098 * getRange(node.getText()) (Reference) 099 */ 100 } 101 } catch (ParseException e) { 102 throw new FormulaCompilationException(e); 103 } 104 } 105 106 // Convert function call 107 Function function = null; 108 try { 109 function = Language.getInstance().getFunction(node.getText()); 110 } catch (UnknownElementException e) { 111 } 112 113 if (function != null) { 114 List<Expression> args = new ArrayList<Expression>(); 115 AST child = node.getFirstChild(); 116 if (function instanceof Eval) { 117 118 try { 119 120 Expression expression = convert(cell, node.getFirstChild()); 121 cell.setContent(expression.evaluate().toText()); 122 } catch (IllegalValueTypeException e) { 123 } 124 125 } 126 if (child != null) { 127 args.add(convert(cell, child)); 128 while ((child = child.getNextSibling()) != null) 129 args.add(convert(cell, child)); 130 } 131 Expression[] argArray = args.toArray(new Expression[args.size()]); 132 return new FunctionCall(function, argArray); 133 } 134 135 if (node.getNumberOfChildren() == 1) 136 // Convert unary operation 137 return new UnaryOperation(Language.getInstance().getUnaryOperator( 138 node.getText()), convert(cell, node.getFirstChild())); 139 else if (node.getNumberOfChildren() == 2) { 140 // Convert binary operation 141 BinaryOperator operator = Language.getInstance().getBinaryOperator( 142 node.getText()); 143 if (operator instanceof RangeReference) 144 return new ReferenceOperation((Reference) convert(cell, 145 node.getFirstChild()), (RangeReference) operator, 146 (Reference) convert(cell, node.getFirstChild() 147 .getNextSibling())); 148 else 149 return new BinaryOperation(convert(cell, node.getFirstChild()), 150 operator, convert(cell, node.getFirstChild() 151 .getNextSibling())); 152 } else 153 // Shouldn't happen 154 throw new FormulaCompilationException(); 155 } 156}