public Boolean visitFullReduceAction(FullReduceAction action)
	throws CopperException
	{
		if(action.getProd().length() >= parseStack.size())
		{
			if(logger.isLoggable(CompilerLogMessageSort.FATAL_ERROR)) logger.logErrorMessage(CompilerLogMessageSort.FATAL_ERROR,currentState.getPos(),"Unable to perform reduction: stack too short");
			return false;
		}
		Object[] children = new Object[action.getProd().length()];
		for(int i = action.getProd().length() - 1;i >= 0;i--)
		{
			children[i] = parseStack.pop().second();
		}
		if(!getParseTable().hasGotoAction(parseStack.peek().first().getStatenum(),action.getProd().getLeft()))
		{
			if(logger.isLoggable(CompilerLogMessageSort.FATAL_ERROR)) logger.logErrorMessage(CompilerLogMessageSort.FATAL_ERROR,currentState.getPos(),"Unable to perform reduction: no goto action available in parse table cell (" + parseStack.peek().first().getStatenum() + "," + action.getProd().getLeft());
			return false;
		}
		ShiftAction gotoAction = getParseTable().getGotoAction(parseStack.peek().first().getStatenum(),action.getProd().getLeft());
		// DEBUG-X-BEGIN
		//System.err.println("Reducing production " + action.getProd());
		// DEBUG-X-END
		Object newNode = null;
		// Will not work with semantic actions that change the lexeme length.
		try { newNode = runSemanticAction(currentState.getPos(),children,action.getProd()); }
		catch(IOException ex)
		{
			reportError("I/O error in semantic action: " + ex.getMessage());
		}
		if(newNode != null && newNode.equals("PARSETREE"))
		{
			ParseTreeNode[] newChildren = new ParseTreeNode[children.length];
			for(int i = 0;i < children.length;i++) newChildren[i] = (ParseTreeNode) children[i];
			ParseTreeProdNode newNodePTPN = parseTree.prodNode(action.getProd(),newChildren); 
			newNode = newNodePTPN;
			parseTree.setRoot(newNodePTPN);
		}
		parseStack.push(Pair.cons(new ParserState(gotoAction.getDestState(),currentState.getPos()),newNode));
		return true;
	}