Statement statement;
	private Statement parseStatement(Preprocessor preprocessor)		throws MapyrusException, IOException	{		int c;		int state = AT_START;		String keyword = null;		Vector expressions = null;		Expression expr;		Statement retval = null;		Vector procedureStatements = null;		Vector procedureParameters = null;		boolean isAssignmentStatement = false;		boolean inProcedureBlock = false;		boolean atEOF = false;		do		{			c = preprocessor.read();			while (true)			{				if (c == -1)				{					/*					 * Reached EOF.					 */					atEOF = true;					break;				}				else if (c == COMMENT_CHAR)				{					/*					 * Found the start of a comment, ignore everything else on line.					 */					state = IN_COMMENT;					c = preprocessor.read();				}				else if (c == '\n')				{					if (keyword.length() > 0)					{						/*						 * End of line signals						 * end of statement.						 */						break;					}					else					{						/*						 * We did not even begin reading						 * a statement so expect to						 * read one on the next line.						 */						state = AT_START;					}					c = preprocessor.read();				}				else if (state == IN_COMMENT)				{					/*					 * Do nothing -- we are reading a comment.					 */					c = preprocessor.read();				}				else if (Character.isWhitespace((char)c))				{					/*					 * Skip whitespace					 */					c = preprocessor.read();				}				else if (state == AT_ARG_SEPARATOR)				{					/*					 * Skip separator between arguments.					 */					if (c != ARGUMENT_SEPARATOR)					{						throw new MapyrusException("Expecting '" +							ARGUMENT_SEPARATOR + "' at " +							preprocessor.getCurrentFilenameAndLine());					}					state = AT_ARG;					c = preprocessor.read();				}				else if (state == AT_PARAM_SEPARATOR)				{					/*					 * Skip separator between parameters.					 */					if (c != ARGUMENT_SEPARATOR)					{						throw new MapyrusException("Expecting '" +							ARGUMENT_SEPARATOR + "' at " +							preprocessor.getCurrentFilenameAndLine());					}					state = AT_BLOCK_PARAM;					c = preprocessor.read();				}				else if (state == AT_START || state == AT_BLOCK_NAME)				{					keyword = parseWord(c, preprocessor);										/*					 * Is this a procedure block definition?					 */					if (state == AT_START && keyword.equalsIgnoreCase(BEGIN_BLOCK))					{						state = AT_BLOCK_NAME;						procedureParameters = new Vector();					}					else if (state == AT_BLOCK_NAME)					{						/*						 * After parsing procedure block name we parse parameters for						 * this procedure block definition.						 */						state = AT_BLOCK_PARAM;					}					else					{						/*						 * After parsing statement we parse arguments to statement.						 */						state = AT_START_ARGS;						expressions = new Vector();					}				}				else if (state == AT_START_ARGS)				{					/*					 * Is this an assignment statement or					 * some other kind of statement?					 */					isAssignmentStatement = (c == '=');					if (isAssignmentStatement)					{						c = preprocessor.read();					}					state = AT_ARG;				}				else if (state == AT_ARG)				{					/*					 * Parse an expression.					 */					preprocessor.unread(c);					expr = new Expression(preprocessor);					expressions.add(expr);					state = AT_ARG_SEPARATOR;				}				else if (state == AT_BLOCK_PARAM)				{					/*					 * Parse a parameter name for procedure block.					 */					procedureParameters.add(parseWord(c, preprocessor));					state = AT_PARAM_SEPARATOR;				}				else				{					/*					 * Parsing is lost.  Don't know what is wrong.					 */					throw new MapyrusException("Error at " +						preprocessor.getCurrentFilenameAndLine());				}			}				/*			 * Build a statement structure for what we just parsed.			 */			if (atEOF && (state == AT_START || state == IN_COMMENT))			{				if (inProcedureBlock)				{					throw new MapyrusException("Unfinished procedure " +						keyword + " at " +						preprocessor.getCurrentFilenameAndLine());				}				/*				 * Could not parse anything before we got EOF.				 */				return(null);			}			else if (state == AT_BLOCK_NAME)			{				/*				 * Began a procedure block but didn't find its name.				 */				throw new MapyrusException("No procedure name given at " +					preprocessor.getCurrentFilenameAndLine());			}			else if (isAssignmentStatement)			{				if (expressions.size() > 1)				{					throw new MapyrusException("Too many expressions in assignment at " +						preprocessor.getCurrentFilenameAndLine());				}				else if (expressions.size() == 0)				{					throw new MapyrusException("No expression in assignment at " +						preprocessor.getCurrentFilenameAndLine());				}				retval = new Statement(keyword,					(Expression)expressions.elementAt(0));			}			else if (keyword.equalsIgnoreCase(END_BLOCK))			{				/*				 * Finish procedure currently being defined.				 */				if (!inProcedureBlock)				{					throw new MapyrusException("Unexpected end of procedure at " +						preprocessor.getCurrentFilenameAndLine());				}				inProcedureBlock = false;								/*				 * Create single statement for all statements making				 * up the procedure.				 */				retval = new Statement(keyword,					procedureParameters,					procedureStatements);			}			else			{				if (state == AT_BLOCK_NAME || state == AT_BLOCK_PARAM)				{					/*					 * Nested procedures are not allowed.					 */					if (inProcedureBlock)					{						throw new MapyrusException("Procedure definition within " +							"existing procedure at " +							preprocessor.getCurrentFilenameAndLine());					}					inProcedureBlock = true;					procedureStatements = new Vector();				}				else				{					Expression []a = new Expression[expressions.size()];					Statement statement;										for (int i = 0; i < a.length; i++)					{						a[i] = (Expression)expressions.elementAt(i);					}					statement = new Statement(keyword, a);					/*					 * Add statement to the procedure we are defining, or					 * return it for immediate execution if we are not defining					 * a procedure.					 */								if (inProcedureBlock)					{						procedureStatements.add(statement);					}					else					{						retval = statement;					}				}			}		}		while (inProcedureBlock);				return(retval);	}