public BValue parseBValue() {
		Token next = tk.next();
		BValue ret;
		
		switch(next.getType()) {
		case Token.TRUE:
			ret = new Bool(true);
			break;
		case Token.FALSE:
			ret = new Bool(false);
			break;
		case Token.VAR: 
			ret = new Variable("v" + Integer.toString(((VarToken) next).getIndex()));
		case Token.NOT:
			tk.next(); //LBracket
			BValue operand = parseBValue();
			tk.next(); //RBracket
			ret = new BooleanOp(BooleanOpType.NOT, operand);
			break;
		case Token.LESS: {
			tk.next(); //LParen
			NValue n1 = parseNValue();
			tk.next(); //Comma
			NValue n2 = parseNValue();
			tk.next(); //RParen
			ret = new ArithmeticRel(ArithmeticRelType.LESS, n1, n2);
			break;
		}
		case Token.EQUAL: {
			tk.next(); //LParen
			NValue n1 = parseNValue();
			tk.next(); //Comma
			NValue n2 = parseNValue();
			tk.next(); //RParen
			ret = new ArithmeticRel(ArithmeticRelType.EQUAL, n1, n2);
			break;
		}
		case Token.GREATER: {
			tk.next(); //LParen
			NValue n1 = parseNValue();
			tk.next(); //Comma
			NValue n2 = parseNValue();
			tk.next(); //RParen
			ret = new ArithmeticRel(ArithmeticRelType.GREATER, n1, n2);
			break;
		}
		default:
			ret = null;
		}
		
		if(tk.peek().getType() == Token.AND) {
			tk.next();//discard the and
			return new BooleanOp(BooleanOpType.AND, ret, parseBValue());
		}
		else if(tk.peek().getType() == Token.OR){
			tk.next();//discard the or
			return new BooleanOp(BooleanOpType.OR, ret, parseBValue());
		}
		else return ret;
	}