This won't work:
cal $day $month $year
cal expects only month and year arguments. Try:
cal $month $year
If you want to print a message if the month and year are invalid, there is no need for a loop. The following code will display a calendar if the month and year are valid or an error message if they are not:
cal $day $month $year 2>/dev/null || echo "Date is not valid."
The statement following || is only executed if the statement preceding it finishes with a non-zero return code (indicating that an error occurred).
Aside
These lines do not appear to accomplish much:
year=$(echo "$year" | bc)
month=$(echo "$month" | bc)
day=$(echo "$day" | bc)
If the variables year, month, and day, are valid, these lines do nothing. If they are not valid numbers, bc will spit out an uncaught error.