The following notes briefly describe how you can use my interpreter classes to implement your spreadsheet interface. The notes are organized as a faq.
The only classes of mine that you will need to explicitly know something about are the following ones:
The API's for these classes get described at the appropriate point in the following faq.
You can parse a new formula that is entered by the user and get it assigned to the appropriate cells using the following calls:
FormulaLexer lex = new FormulaLexer(new ANTLRReaderStream(new StringReader(formula string))); CommonTokenStream tokens = new CommonTokenStream(lex); FormulaParser formulaParser = new FormulaParser(tokens); LinkedList<Cell> changedCells = formulaParser.prog();formula string is the string the user enters in the formula text box. changedCells is a list of Cell objects that were assigned the new formula. If the formula was a specific formula, like "b[1] = a[1]", there will be only one Cell object on the list. If the formula was a generic formula, like "b[i=1-4,8] = a[i]", then there will be multiple Cell objects on the list.
After you have called the parser to parse your formula, you can make the following call to both evaluate the new formula, and to update any cells that depend on cells to which the new formula was assigned:
Cell.updateCells();For example, suppose the user entered the formula c[5] = b[5] + a[5]. Further suppose that cell c[6] has the formula c[6] = c[5] * 2. Then updateCells will evaluate both c[5] and c[6].
The method LinkedList <Cell> Cell.updateCells returns a linked list of the cells whose values have changed, either because a new formula was assigned to the cell, or because the cell depended directly or indirectly on a cell that was assigned a new formula.
Alternatively, you can simply iterate through all the JLabels/JTextFields in your spreadsheet, and for each one, query the associated Cell object for its value. This alternative approach does not require you to know which cells have changed, since you will update all of the labels using a brute force traversal.
If you have a column label (e.g., "b") and a row index (e.g., 3), then the class VarExp has a static method named getCell that you can use to obtain a pointer to that cell's object. For example:
Cell b3 = VarExp.getCell("b", 3);
You can use the Cell class's getValue method to return the numeric value of a cell. However, first make sure that you have called Cell.updateCells() to update all the cells in the spreadsheet. You will also need to obtain a pointer to the cell's object, either through a stored pointer or through a call to the VarExp class's getCell method.
The Cell class has a method named isUndef that returns a boolean that indicates whether or not a cell object's value is undefined. Note that a cell may be undefined either because its formula depends on an undefined cell and hence cannot be evaluated, or because the cell was never assigned a formula. If the cell was never assigned a formula it should appear as a blank field in the spreadsheet, whereas if its formula cannot be evaluated, its value should be shown as "undef" in the spreadsheet. The Cell class has a method named getFormula that returns a pointer to a Formula object if one exists, and null otherwise. You can test the pointer to determine whether or not the cell has ever been assigned a formula.
The Cell class has a method named getUndefExplanation that returns a String which you can display to the user. If no formula has been assigned to this cell, the string will explain that no formula has ever been assigned to this cell. If the formula cannot be evaluated because it depends on an undefined cell, then the string specifies which cell this formula depends on that is undefined.
The Cell class has a method named setFormulaExpression that you can use to store a formula's text string with a cell, and a method named getFormulaExpression that you can use to retrieve this string. For example,
Cell c; c.setFormulaExpression("a[i=3-6] = b[i] * c[i]"); String formulaString = c.getFormulaExpression();You will need to call setFormulaExpression on each cell that is assigned a formula by the parser. My parser will return a linked list of cell objects, and you can iterate through them and set each one to point to the string for this formula. For example:
LinkedList<Cell> changedCells = formulaParser.prog(); // record the text version of the formula in each cell // to which it was assigned for (Cell cell : changedCells) { cell.setFormulaExpression(formula string) }formula string would be the string the user enters in the formula text box. Antlr does not provide a way of getting at the original string that is passed to the parser, so the parser cannot be responsible for storing the formula string into a cell.
My parser detects both syntactic and semantic errors, such as a non-integer row index, a row index that is out-of-range (my parser limits row subscripts to be from 1-10), or a reference to an undefined column label. It handles both types of errors by throwing exceptions that should be caught by the action handler for your formula text box.
Syntactic errors are thrown as RecognitionException objects. You can display a simple error message, such as "Syntax error", for syntax errors, because Antlr does not provide helpful messages. In fact, the messages would be confusing for an end user, so "Syntax error" is fine.
Semantic errors are thrown as SemanticError objects. You can retrieve their error message using the getMessage method and display it in a dialog box.
Your code will discover that a cell is undefined when it starts to update the labels for the cells in the spreadsheet. It will query the Cell's isUndef method and find out that the cell is undefined. It can then display "undef" as the cell's value.
Here is the public API for the Cell class. The notes have discussed this class but here is a summary of helpful methods:
Before printing the value of a cell your code should check to see whether the cell's value is undefined. If so you should print "Undef" in the cell's field rather than a floating point number.
Here is the public API for the VarExp class. The notes have discussed this class but here is a summary of helpful methods: