People tried, believe me: back when running compilers as batch jobs i.e. non-interactively was the norm, it was expected for them to find as many syntax errors as possible in one go, so the programmer could fix as much of his program as possible before resubmitting it.
But yes, simple "when parsing list of X, skip until you find something that looks like the end of X (or start of another X/whatever is expected after the list of X) and try to parse another X" works surprisingly well, especially in statement-oriented (block-oriented?) languages: you can almost always reliably detect an end of the block/function or a start of top-level declaration and start from that point.
The most difficult to sensibly catch error, in my experience, happens inside the lexer: the case of a run-away string. Add a random quote mark in the middle of program text and suddenly, everything after it produces completely different, mostly nonsensical, stream of tokens.