#! /usr/bin/env perl
#
# C source compressor. This:
#
# - merges continuation lines
# - removes comments (not in strings)
# - removes empty lines (not in strings)
use strict;
use warnings;
my $debug = defined $ENV{DEBUG};
my $lang = shift @ARGV;
# Slurp the file
$/ = undef;
$_ = <>;
if ($lang eq 'C') {
# Merge continuation lines
s{\\\n}{}g;
# Regexp for things that should be preserved
my $preserved =
qr{
(?:
" # String start
(?: \\. | [^\"])* # Any character, including escaped ones
" # String end
)
| # OR
(?:
' # Character start (multi-chars supported)
(?: \\. | [^\'])+ # Any character, including escaped ones
' # String end
)
}x;
# Remove comments while preserving strings
s{
(?| # All things preserved end up in $1
/\* # C comment start
.*? # Contents up until
\*/ # C comment end
| # OR
( # Grouping for the replacement
$preserved
)
)
}{
if ($debug) {
print STDERR "DEBUG: '$&' => '$1'\n" if defined $1;
print STDERR "DEBUG: '$&' removed\n" unless defined $1;
}
defined $1 ? $1 : ""
}gsxe;
# Remove empty lines
s{
(?| # All things preserved end up in $1
(^|\n)(?:\s*(?:\n|$))+ # Empty lines, preserve one newline
| # OR
( # Grouping for the replacement
$preserved
)
)
}{$1}gsx;
# Remove extra spaces
s{
(?| # All things preserved end up in $1
\h+ # Horizontal spaces replaced with one
| # OR
( # Grouping for the replacement
$preserved
)
)
}{
if ($debug) {
print STDERR "DEBUG: '$&' => '$1'\n" if defined $1;
print STDERR "DEBUG: '$&' => ' '\n" unless defined $1;
}
defined $1 ? $1 : " "
}gsxe;
# Clean up spaces at start and end of lines
s/^ //mg;
s/ $//mg;
} elsif ($lang eq 'S') {
# Because we use C++ style comments in our .S files, all we can do
# is to drop them
s{
^([^\n]*?)//[^\n]*?$ # Any line with a // comment
}{
if ($debug) {
print STDERR "DEBUG: '$&' => '$1'\n" if defined $1;
print STDERR "DEBUG: '$&' removed\n" unless defined $1;
}
defined $1 ? $1 : ""
}mgsxe;
# Drop all empty lines
s{
(^|\n)(?:\s*(?:\n|$))+ # Empty lines, preserve one newline
}{$1}gsx;
} elsif ($lang eq 'perl') {
# Merge continuation lines
s{\\\n}{}g;
# Regexp for things that should be preserved
my $preserved =
qr{
(?:
<<["']?(\w+)["']? # HERE document start
.*? # Its contents
^\g{-1}$
)
|
(?:
" # Double quoted string start
(?: \\. | [^\"])* # Any character, including escaped ones
" # Double quoted string end
)
| # OR
(?:
' # Single quoted string start
[^\']* # Any character
' # Single quoted string end
)
}msx;
# Remove comments while preserving strings
s{
(?| # All things preserved end up in $1
\#.*?(\n|$) # Perl comments
| # OR
( # Grouping for the replacement
$preserved
)
)
}{
if ($debug) {
print STDERR "DEBUG: '$&' => '$1'\n" if defined $1;
print STDERR "DEBUG: '$&' removed\n" unless defined $1;
}
defined $1 ? $1 : ""
}gsxe;
# Remove empty lines
s{
(?| # All things preserved end up in $1
(^|\n)(?:\s*(?:\n|$))+ # Empty lines, preserve one newline
| # OR
( # Grouping for the replacement
$preserved
)
)
}{$1}gsx;
}
print;