Think I've got it...
while ($_ = <STDIN>)
{
chomp;
s/^((([^\#\\])|(\\.))*)\#.*$/$1/;
print "$_\n";
}
Seems to do the trick, assuming record delimiters in STDIN are correctly set. Basically, the regexp matches anything that isn't a comment or a quote character, *or* anything that's a quote character followed by anything. Because perl is greedy, this matches up to the first unquoted comment character, and we just substitute away anything after that...
I think substituting out the quotes themselves requires another s/// statement, but it's fairly trivial ;-)