The following notes briefly describe how you can use my interpreter classes to implement your spreadsheet interface. The notes are organized as a faq.


How Do I Get Started?

  1. You should copy the ~bvz/cs365/project/project4/formula directory to your formula directory.
  2. You will then add your interface classes to your formula directory. The spreadsheet.java class will be one of your interface classes. You may create additional ones as you see fit.
  3. Make sure that you import org.antlr.runtime.*. If you fail to do so, you will get dozens of compiler error messages that related to Antlr classes that cannot be found.

The only classes of mine that you will need to explicitly know something about are the following ones:

  1. Cell: A class that contains all the information needed for a specific cell in the spreadsheet. Each JLabel or JTextField that you have in your spreadsheet should contain a pointer to a cell object. Among other things, a Cell object keeps track of the cell's formula, value, the string that defines the cell's formula, and whether or not the cell's value is undefined.
  2. VarExp: A class that contains a number of static methods for creating cells, setting cells to point to new formulas, and obtaining pointers to cells using a column label and row subscript as a key.
  3. FormulaParser: The Antlr generated class for parsing a string into a formula object and assigning that formula object to the appropriate Cell objects.
  4. FormulaLexer: The Antlr generated class for breaking a string into tokens that can be fed into FormulaParser.

The API's for these classes get described at the appropriate point in the following faq.


How Do I Parse A Formula?

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.


How Do I Get The Interpreter To Evaluate New Formulas?

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].


How Can I Determine Which Cells Have Changed In The Spreadsheet?

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.


How Can I Get A Pointer To A Cell Object?

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);


How Can I Access A Cell's Value?

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.


How Do I Know If A Cell's Value Is Undefined?

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.


How Do I Determine Why A Cell's Formula Is Undefined?

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.


How Can I Display A Cell's Formula?

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.


What Errors Are Detected By The Parser?

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.


What Happens When A Formula Depends On An Undefined Cell?

My formula interpreter will detect such an error during the call to Cell.updateCells. It will silently catch the exception and assign an appropriate string to the undefinedExplanation field of the cell to which the formula belongs. It will also mark the cell as undefined. It will then continue evaluating the other cells in the spreadsheet.

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.


The Cell Class: A Brief Reference

Here is the public API for the Cell class. The notes have discussed this class but here is a summary of helpful methods:


The VarExp Class: A Brief Reference

Here is the public API for the VarExp class. The notes have discussed this class but here is a summary of helpful methods: