BitSet expression(Token[] code, int pcStart) throws ScriptException {
		isExpressionBitSet = false;
		BitSet bs;
		BitSet[] stack = new BitSet[10];
		int sp = 0;
		Point3f thisCoordinate = null;
		boolean refreshed = false;
		pcLastExpressionInstruction = 1000;
		boolean isSubsetDefinition = (pcStart < 0);
		if (isSubsetDefinition)
			pcStart = -pcStart;
		if (logMessages)
			viewer.scriptStatus("start to evaluate expression");
		expression_loop: for (int pc = pcStart;; ++pc) {
			Token instruction = code[pc];
			if (logMessages)
				viewer.scriptStatus("instruction=" + instruction);
			switch (instruction.tok) {
			case Token.expressionBegin:
				break;
			case Token.expressionEnd:
				pcLastExpressionInstruction = pc;
				break expression_loop;
			case Token.leftbrace:
				thisCoordinate = getCoordinate(pc, true);
				pc = pcLastExpressionInstruction;
				break;
			case Token.all:
				bs = stack[sp++] = bsAll();
				break;
			case Token.none:
				stack[sp++] = new BitSet();
				break;
			case Token.opOr:
				bs = stack[--sp];
				stack[sp - 1].or(bs);
				break;
			case Token.opXor:
				bs = stack[--sp];
				stack[sp - 1].xor(bs);
				break;
			case Token.opAnd:
				bs = stack[--sp];
				stack[sp - 1].and(bs);
				break;
			case Token.opNot:
				bs = stack[sp - 1];
				notSet(bs);
				break;
			case Token.opToggle:
				bs = stack[--sp];
				toggle(stack[sp - 1], bs);
				break;
			case Token.within:
				if (thisCoordinate != null) {
					Object withinSpec = instruction.value;
					if (!(withinSpec instanceof Float))
						numberExpected();
					stack[sp++] = viewer.getAtomsWithin(((Float) withinSpec).floatValue(), thisCoordinate);
					thisCoordinate = null;
					break;
				}
				bs = stack[sp - 1];
				stack[sp - 1] = within(instruction, bs);
				break;
			case Token.connected:
				bs = stack[sp - 1];
				stack[sp - 1] = connected(instruction, bs);
				break;
			case Token.substructure:
				stack[sp++] = getSubstructureSet((String) instruction.value);
				break;
			case Token.selected:
				stack[sp++] = copyBitSet(viewer.getSelectionSet());
				break;
			case Token.subset:
				stack[sp++] = copyBitSet(bsSubset == null ? bsAll() : bsSubset);
				break;
			case Token.hidden:
				stack[sp++] = copyBitSet(viewer.getHiddenSet());
				break;
			case Token.displayed:
				stack[sp++] = invertBitSet(viewer.getHiddenSet());
				break;
			case Token.visible:
				if (!refreshed)
					viewer.setModelVisibility();
				refreshed = true;
				stack[sp++] = viewer.getVisibleSet();
				break;
			case Token.clickable:
				refresh();
				stack[sp++] = viewer.getClickableSet();
				break;
			case Token.specialposition:
			case Token.symmetry:
			case Token.unitcell:
			case Token.hetero:
			case Token.hydrogen:
			case Token.protein:
			case Token.nucleic:
			case Token.dna:
			case Token.rna:
			case Token.carbohydrate:
			case Token.purine:
			case Token.pyrimidine:
				stack[sp++] = viewer.getAtomBits((String) instruction.value);
				break;
			case Token.spec_atom:
				stack[sp++] = viewer.getAtomBits("SpecAtom", (String) instruction.value);
				break;
			case Token.spec_name_pattern:
				stack[sp++] = viewer.getAtomBits("SpecName", (String) instruction.value);
				break;
			case Token.bitset:
				stack[sp++] = (BitSet) instruction.value;
				isExpressionBitSet = true;
				break;
			case Token.spec_alternate:
				stack[sp++] = viewer.getAtomBits("SpecAlternate", (String) instruction.value);
				break;
			case Token.spec_model:
				stack[sp++] = viewer.getAtomBits("SpecModel", (String) instruction.value);
				break;
			case Token.spec_resid:
				stack[sp++] = viewer.getAtomBits("SpecResid", instruction.intValue);
				break;
			case Token.spec_seqcode:
				stack[sp++] = viewer.getAtomBits("SpecSeqcode", instruction.intValue);
				break;
			case Token.spec_chain:
				stack[sp++] = viewer.getAtomBits("SpecChain", instruction.intValue);
				break;
			case Token.spec_seqcode_range:
				int seqcodeA = instruction.intValue;
				int seqcodeB = ((Integer) instruction.value).intValue();
				stack[sp++] = viewer.getAtomBits("SpecSeqcodeRange", new int[] { seqcodeA, seqcodeB });
				break;
			case Token.cell:
				Point3f pt = (Point3f) instruction.value;
				stack[sp++] = viewer.getAtomBits("Cell", new int[] { (int) (pt.x * 1000), (int) (pt.y * 1000),
						(int) (pt.z * 1000) });
				break;
			case Token.identifier:
			case Token.amino:
			case Token.backbone:
			case Token.solvent:
			case Token.sidechain:
			case Token.surface:
				stack[sp++] = lookupIdentifierValue((String) instruction.value);
				break;
			case Token.opLT:
			case Token.opLE:
			case Token.opGE:
			case Token.opGT:
			case Token.opEQ:
			case Token.opNE:
				bs = stack[sp++] = new BitSet();
				comparatorInstruction(instruction, bs);
				break;
			default:
				unrecognizedExpression();
			}
		}
		if (sp != 1)
			evalError(GT._("atom expression compiler error - stack over/underflow"));
		if (!isSubsetDefinition && bsSubset != null)
			stack[0].and(bsSubset);
		return stack[0];
	}