// Joseph Bergin// Pace University// April, 1996import java.util.Random;import java.lang.Math;import java.awt.*;import java.applet.*;import java.awt.event.*;import java.util.*;import java.io.*;class SpreadsheetCell{	// instructions. These inner classes define the execution model. This execution	// language does not have any jump instructions. Only sequential execution is 	// supported. 	abstract class Instruction	{	public abstract void execute();	}		class Pushi extends Instruction // push a literal integer	{	public Pushi(int i) { value = i; }			public void execute()		{	evaluationStack.push(new Integer(value));		}				private int value;	}		class Pushv extends Instruction // push the value of a particular cell	{	public Pushv(SpreadsheetCell which) { this.which = which; }			public void execute()		{	evaluationStack.push(new Integer(which.evaluate()));		}				private SpreadsheetCell which;	}	class Pop extends Instruction // not used here.	{	public void execute()		{	evaluationStack.pop();		}	}		class Sum extends Instruction //Add the two top elements in the stack.	{	public void execute()		{	Integer Rtemp = (Integer)evaluationStack.pop();			Integer Ltemp = (Integer)evaluationStack.pop();			evaluationStack.push(new Integer(Ltemp.intValue() + Rtemp.intValue()));		}	}		class Difference extends Instruction	{	public void execute()		{	Integer Rtemp = (Integer)evaluationStack.pop();			Integer Ltemp = (Integer)evaluationStack.pop();			evaluationStack.push(new Integer(Ltemp.intValue() - Rtemp.intValue()));		}	}		class Product extends Instruction	{	public void execute()		{	Integer Rtemp = (Integer)evaluationStack.pop();			Integer Ltemp = (Integer)evaluationStack.pop();			evaluationStack.push(new Integer(Ltemp.intValue() * Rtemp.intValue()));		}	}		class Quotient extends Instruction	{	public void execute()		{	Integer Rtemp = (Integer)evaluationStack.pop();			Integer Ltemp = (Integer)evaluationStack.pop();			evaluationStack.push(new Integer(Ltemp.intValue() / Rtemp.intValue()));		}	}			static boolean isLetter(char c)	{	return (c>='a' && c<='z') || (c>='A' && c<='Z');	}		static boolean isDigit(char c)	{	return (c>='0' && c<='9');	}	static boolean legalCellSpelling(String s)	{	int i;		if(!isLetter(s.charAt(0))) return false;		if(s.length() < 2) return false;		for(i = 1; i < s.length(); ++i)		{	if(!isDigit(s.charAt(i)))				return false;		}		return true;	}	static int extractColumn(String s) // assumed to be legal	{	return s.charAt(0) - 'a';	}	static int extractRow(String s) // assumed to be legal	{	int i, result = 0;		for(i=1; i< s.length(); ++i)		{	if(!isDigit(s.charAt(i))) break;			result = 10*result + (s.charAt(i) - '0');		}		return result;	}	int evaluate()  // To evaluate a cell we need to execute its program if it has one. 	{	Integer Rtemp,Ltemp;		if(!_isEvaluated)		{	//System.out.println("eval"+_row+" "+_col+" "+_programLength);			for(int i = 0; i<_programLength; ++i)			{	((Instruction)_program.elementAt(i)).execute();			}			Integer temp = (Integer)evaluationStack.pop();			_value = temp.intValue();		}		//System.out.println("value "+_value);		_isEvaluated = true;		return _value;	}		String name()	{	return String.valueOf('a' + _col).concat(String.valueOf(_row));	}		void mark()	{	_isEvaluated = _hasValue;	}		void parse() // parses rhs of an assignment command using the expression grammar.	// The technique used is recursive descent, a simple but powerful compiler technique. 	// As we parse, we build up a new program for the cell. This program can later be 	// executed to obtain a value for the cell. 	{	_programLength = 0; // start with a new program		_hasValue = false; // no value yet		parseexpression(); 		scanner.match(scanner.semicolon);	// Ths parser is recursive descent, based on the grammar for <expression>, below.	}		void parseexpression()	{	parseterm();		parseaddopterm();	}		void parseterm()	{	parsefactor();  		parsemulopfactor();	}		void parseaddopterm()	{	Instruction op;		if(scanner.nextToken() == scanner.plusop || scanner.nextToken() == scanner.minusop)		{	if (scanner.nextToken() == scanner.minusop) 				op = new Difference();			else				op = new Sum();			scanner.toss();			parseterm();			_programLength++;			_program.addElement(op);				_hasValue = false;				parseaddopterm();		}	}	void parsemulopfactor()	{	Instruction op;		if(scanner.nextToken() == scanner.timesop || scanner.nextToken() == scanner.divideop)		{	if (scanner.nextToken() == scanner.divideop) 				op = new Quotient();			else				op = new Product();			scanner.toss();			parsefactor();			_programLength++;			_program.addElement(op);				_hasValue = false;				parsemulopfactor();		}	}		void parsefactor()	{	switch (scanner.nextToken()) 		{	case scanner.lparen:			{	scanner.match(scanner.lparen);				parseexpression();				scanner.match(scanner.rparen);				break;			}			case scanner.identifier:			{	int row, col;				row = extractRow(scanner.which);				col = extractColumn(scanner.which);				if(!_sheet.legalCell(col,row))scanner.parseError("Illegal cell. "+col+" "+row);				scanner.toss();				_programLength++;				_program.addElement( new Pushv(_sheet._cells[col][row]));					_hasValue = false;				break;			}			case scanner.number:			{	int value = scanner.value;				scanner.toss();				_programLength++;				_program.addElement( new Pushi(value));					_hasValue = true;					_value = value;				break;			}  			case scanner.sumfunc:			case scanner.prodfunc:			{	Instruction op;				if(scanner.nextToken() == scanner.prodfunc)					op = new Product();				else					op = new Sum();				scanner.toss();				scanner.match(scanner.lparen);				int lr=-1,lc=-1,rr=-1,rc=-1; // leftrow...				if(scanner.nextToken() == scanner.identifier && legalCellSpelling(scanner.which))				{	lc = extractColumn(scanner.which);					lr = extractRow(scanner.which);					scanner.toss();				}					else					scanner.parseError("Illegal range "+lc+" "+lr);				scanner.match(scanner.rangeop);				if(scanner.nextToken() == scanner.identifier && legalCellSpelling(scanner.which))				{	rc = extractColumn(scanner.which);					rr = extractRow(scanner.which);					scanner.toss();				}				else					scanner.parseError("Illegal range "+rc+" "+rr);				scanner.match(scanner.rparen);				int temp;				if(lc > rc){temp = lc; lc = rc; rc = temp;}				if(lr > rr){temp = lr; lr = rr; rr = temp;}				if(!_sheet.legalCell(lc,lr))scanner.parseError("Illegal range "+lc+" "+lr);				if(!_sheet.legalCell(rc,rr))scanner.parseError("Illegal range "+rc+" "+rr);				int cellcount = (rc - lc +1) * (rr - lr + 1);				_programLength++;				_program.addElement( new Pushv( _sheet._cells[lc][lr]));					for(int i = lr; i<= rr; i++)					for(int j = lc; j<=rc; j++)					{	if(i!=lr || j != lc)						{	_programLength++;							_program.addElement( new Pushv(_sheet._cells[j][i]));								_programLength++;							_program.addElement( op);							}					}				break;			}		}	}		boolean _hasValue = true;  // ifFalse: hasProgram	boolean _isEvaluated = false;		Vector _program = new Vector(10); // initial size is 10. It will grow as needed. 	// The vector contains instruction objects. 	static Stack evaluationStack = new Stack();	Scanner scanner;			int _programLength = 0; // Current number of instructions stored	int _value = 0;	SpreadsheetModel  _sheet = null;   	int _row, _col; // Where this cell is in the Sheet.}class SpreadsheetModel{	public SpreadsheetModel( int columns,  int rows, Scanner scan ) //up to 26 COLUMNS 	{	scanner = scan;		_rows = rows;		_columns = columns;		_cells = new SpreadsheetCell[columns][rows];		if(columns > 26) throw (new IllegalArgumentException("Too many columns in Spreadsheet."));		for(int i = 0; i<columns; i++)			for(int j=0; j<rows; j++)			{	_cells[i][j] = new SpreadsheetCell();				_cells[i][j]._sheet = this;				_cells[i][j]._row = j;				_cells[i][j]._col = i; 				_cells[i][j].scanner = scanner; 			}	}	public void draw()// show evaluated values	{ // not used here	}	public void dump()// show cell contents (values or programs).	{ // not used here	}	public void evaluate()	// Update all the cells.	{	int i,j;		for(i = 0; i<_columns; i++)			for(j = 0; j<_rows; j++)				_cells[i][j].mark();		for(i = 0; i<_columns; i++)			for(j = 0; j<_rows; j++)				if(!_cells[i][j]._isEvaluated)					_cells[i][j].evaluate();	}	public boolean parse()  // parses lhs of a command; // return false at end	{	String which;			if (scanner.nextToken() == scanner.identifier) 		{	which = scanner.which;			scanner.toss();		} 		else		{	scanner.parseError("Illegal command. Letter expected.");			scanner.toss();			return true;		}				if(which.equals( "done"))		{	 // not used here			return false;		}				if(which.equals("eval")) 		{	evaluate();		}		else if(which.equals( "print"))		{	 // not used here			draw();		}		else if(which.equals( "dump")) // dump sheet details to System.out		{	 // not used here			dump();		}		else if (SpreadsheetCell.legalCellSpelling(which))		{	scanner.match(scanner.assignop);			int i,j;			j = SpreadsheetCell.extractRow(which);			i = SpreadsheetCell.extractColumn(which);			if(!legalCell(i,j)) 			{	scanner.parseError("Illegal cell: " + which);				return true;			}			_cells[i][j].parse();		}		else		{	scanner.parseError("Illegal cell/command: " + which);		}			return true;	}	public boolean legalCell( int col, int row) // Are (row,col) legal?	{	return col<_columns && row < _rows;	}	SpreadsheetCell [][] _cells;	int _rows;	int _columns;	Scanner scanner;}public class Spreadsheet extends Applet // This defines the view of the spreadsheet. {		public String getAppletInfo()	{	return "Spread Sheet. Joseph Bergin. April 1996";	}		public String[][] getParameterInfo()	{	String[][] result = 		{	{"rows","integer",  "Number of rows in Spread Sheet."},			{"columns", "integer", "Number of columns in Spread Sheet. Up to 26."}		};		return result;	}		int getSSParameter(String name)	{	String value = getParameter(name);		int result;		try{ result = Integer.parseInt(value, 10); }		catch (NumberFormatException e){ return 0; }		return result;	}			public void init()	{	commands = new TextField("Welcome",30);		commands.setEditable(true);			messages = new TextField("Spread Sheet",30);		messages.setEditable(false);			scanner = new Scanner(commands);		scanner.setErrorField(messages);		int ssRows = getSSParameter("rows");		int ssColumns = getSSParameter("columns");		theSheet = new SpreadsheetModel(ssColumns, ssRows, scanner);		setLayout(new BorderLayout());				Panel IO = new Panel();		IO.setLayout(new FlowLayout());		IO.add("North", messages);		add("North", IO);		Panel SS = new Panel();		SS.setLayout(new GridLayout(ssRows, ssColumns, 1, 1));		theSheetCellViews = new TextField[ssColumns][ssRows];		for(int j = 0; j<ssRows; j++)			for(int i = 0; i<ssColumns; i++)			{	theSheetCellViews[i][j] = new TextField("", 10);				theSheetCellViews[i][j].setText("r"+i+" c"+j);				theSheetCellViews[i][j].setEditable(false);				SS.add(theSheetCellViews[i][j]);			}		add("Center", SS);				Panel P = new Panel();		Label L = new Label("Commands ");		L.setFont(new Font("Times", Font.BOLD, 10));		P.add("East", L);		P.add("North", commands);		Button b, e, c;		P.add("South",b = new Button("Accept"));		b.addActionListener(new AcceptListener());		P.add(e = new Button("Evaluate"));		e.addActionListener(new EvaluateListener());		P.add(c = new Button("Clear"));		c.addActionListener(new ClearListener());		add("South", P);					}		class AcceptListener implements ActionListener	{	public void actionPerformed(ActionEvent e)		{	scanner.toss();			messages.setText("");			theSheet.parse();			//messages.setText("..Accepted..");		}	}	class EvaluateListener implements ActionListener	{	public void actionPerformed(ActionEvent e)		{	messages.setText("");			theSheet.evaluate();			//messages.setText("..Evaluate..");			paint(getGraphics());	 		}	}		class ClearListener implements ActionListener	{	public void actionPerformed(ActionEvent e)		{	commands.setText("");		}	}		public void paint(Graphics g)	{	for(int i = 0; i < theSheet._rows; i++)			for(int j = 0; j < theSheet._columns; j++)				theSheetCellViews[j][i].setText(" "+theSheet._cells[j][i]._value);		super.paint(g);	}		private TextField commands, messages;	private SpreadsheetModel theSheet;	private Scanner scanner;	private TextField[][] theSheetCellViews;}/*	The statements that may be entered are as follows:<statement>		::= <assign> ";" | <command><assign>		::= "letter" "=" <expression><expression>	::= <term> <plusopterm><plusopterm>	::= "" | ("+" | "-") <term> <plusopterm><term>			::= <factor> <mulopfactor><mulopfactor>	::= "" | ("*" | "/") <factor> <mulopfactor><factor>		::= "number" | "letter" | "(" <expression? ")" 					| "sum" "(" <range> ")" | "prod" "(" <range> ")" <range>			::=	"letter" ".." "letter"<command>		::= "eval" | "print" | "dump" | "done" "letter"	is a single letter followed by an integer (both in legal range): e.g. a4."number"	is an unsigned integer.  To get -5 use 0-5.  There is no unary minus. Sorry.*/// example commands//  A6 = 5;			// The letter names the column and the integer the row. //	B8 = A6 + 1;	// also elaborate expressions with operators +-*/ and parens.//  A9 = sum(B1..C4);	// also prod(range)  where range == cell..cell// NOTE: A recursive command (e.g. A0=A0+1) is illegal. There is no check for it in this// program however.  Your program will eventually crash if you try it. It is also possible// to write mutually recursive sets of commands.  These are just as illegal.   /* Exercises:  (In approximate increasing order of difficulty )	Add a unary minus.  Use ~ for this operator, not -.  ~5 means minus 5. 	Add the modulo operator to the language. Use % for this operator.  12 % 5 should		 yield 2. 	Give the program a prettier interface. 	Add an additional range function. Choose a good one.  	Optimize the operations a bit. What happens if we add zero to something? Can you 		improve this? Note that here we create a new object to hold the sum. 	Add an exponentiation operator. Use ^ for this operator.  2^5 should yield 32.		The precidence level of ^ should be higher than that of * and /, but lower than 		parens. Note that if you permit 2^5^3, that it should group from the right 		as 2^(5^3).  The included operators all group from the left within precidence 		levels. 		Add a logic operator similar to the C++ conditional expression operator ?:.  To the 		left of the ? you need a comparison like a4<3.  To the right you need two 		expressions separated by the colon.  	What improvements can you make that will increase the total code size by no more than 		one page?	Guarantee that recursive programs are caught before they are evaluated. */