#!/bin/perl $indent = 4; $shiftwidth = 4; $l = '{'; $r = '}'; $tempvar = '1'; while ($ARGV[0] =~ '^-') { $_ = shift; last if /^--/; if (/^-D/) { $debug++; open(body,'>-'); next; } if (/^-n/) { $assumen++; next; } if (/^-p/) { $assumep++; next; } die "I don't recognize this switch: $_"; } unless ($debug) { open(body,">/tmp/sperl$$") || do Die("Can't open temp file."); } if (!$assumen && !$assumep) { print body 'while ($ARGV[0] =~ /^-/) { $_ = shift; last if /^--/; if (/^-n/) { $nflag++; next; } die "I don\'t recognize this switch: $_"; } '; } print body ' #ifdef PRINTIT #ifdef ASSUMEP $printit++; #else $printit++ unless $nflag; #endif #endif line: while (<>) { '; line: while (<>) { s/[ \t]*(.*)\n$/$1/; if (/^:/) { s/^:[ \t]*//; $label = do make_label($_); if ($. == 1) { $toplabel = $label; } $_ = "$label:"; if ($lastlinewaslabel++) {$_ .= "\t;";} if ($indent >= 2) { $indent -= 2; $indmod = 2; } next; } else { $lastlinewaslabel = ''; } $addr1 = ''; $addr2 = ''; if (s/^([0-9]+)//) { $addr1 = "$1"; } elsif (s/^\$//) { $addr1 = 'eof()'; } elsif (s|^/||) { $addr1 = '/'; delim: while (s:^([^(|)\\/]*)([(|)\\/])::) { $prefix = $1; $delim = $2; if ($delim eq '\\') { s/(.)(.*)/$2/; $ch = $1; $delim = '' if index("(|)",$ch) >= 0; $delim .= $1; } elsif ($delim ne '/') { $delim = '\\' . $delim; } $addr1 .= $prefix; $addr1 .= $delim; if ($delim eq '/') { last delim; } } } if (s/^,//) { if (s/^([0-9]+)//) { $addr2 = "$1"; } elsif (s/^\$//) { $addr2 = "eof()"; } elsif (s|^/||) { $addr2 = '/'; delim: while (s:^([^(|)\\/]*)([(|)\\/])::) { $prefix = $1; $delim = $2; if ($delim eq '\\') { s/(.)(.*)/$2/; $ch = $1; $delim = '' if index("(|)",$ch) >= 0; $delim .= $1; } elsif ($delim ne '/') { $delim = '\\' . $delim; } $addr2 .= $prefix; $addr2 .= $delim; if ($delim eq '/') { last delim; } } } else { do Die("Invalid second address at line $.: $_"); } $addr1 .= " .. $addr2"; } # a { to keep vi happy if ($_ eq '}') { $indent -= 4; next; } if (s/^!//) { $if = 'unless'; $else = "$r else $l\n"; } else { $if = 'if'; $else = ''; } if (s/^{//) { # a } to keep vi happy $indmod = 4; $redo = $_; $_ = ''; $rmaybe = ''; } else { $rmaybe = "\n$r"; if ($addr2 || $addr1) { $space = substr(' ',0,$shiftwidth); } else { $space = ''; } $_ = do transmogrify(); } if ($addr1) { if ($_ !~ /[\n{}]/ && $rmaybe && !$change && $_ !~ / if / && $_ !~ / unless /) { s/;$/ $if $addr1;/; $_ = substr($_,$shiftwidth,1000); } else { $command = $_; $_ = "$if ($addr1) $l\n$change$command$rmaybe"; } $change = ''; next line; } } continue { @lines = split(/\n/,$_); while ($#lines >= 0) { $_ = shift(lines); unless (s/^ *<<--//) { print body substr("\t\t\t\t\t\t\t\t\t\t\t\t",0,$indent / 8), substr(' ',0,$indent % 8); } print body $_, "\n"; } $indent += $indmod; $indmod = 0; if ($redo) { $_ = $redo; $redo = ''; redo line; } } print body "}\n"; if ($appendseen || $tseen || !$assumen) { $printit++ if $dseen || (!$assumen && !$assumep); print body ' continue { #ifdef PRINTIT #ifdef DSEEN #ifdef ASSUMEP print if $printit++; #else if ($printit) { print;} else { $printit++ unless $nflag; } #endif #else print if $printit; #endif #else print; #endif #ifdef TSEEN $tflag = \'\'; #endif #ifdef APPENDSEEN if ($atext) { print $atext; $atext = \'\'; } #endif } '; } close body; unless ($debug) { open(head,">/tmp/sperl2$$") || do Die("Can't open temp file 2.\n"); print head "#define PRINTIT\n" if ($printit); print head "#define APPENDSEEN\n" if ($appendseen); print head "#define TSEEN\n" if ($tseen); print head "#define DSEEN\n" if ($dseen); print head "#define ASSUMEN\n" if ($assumen); print head "#define ASSUMEP\n" if ($assumep); if ($opens) {print head "$opens\n";} open(body,"/tmp/sperl$$") || do Die("Can't reopen temp file."); while () { print head $_; } close head; print "#!/bin/perl\n\n"; open(body,"cc -E /tmp/sperl2$$ |") || do Die("Can't reopen temp file."); while () { /^# [0-9]/ && next; /^[ \t]*$/ && next; s/^<><>//; print; } } `/bin/rm -f /tmp/sperl$$ /tmp/sperl2$$`; sub Die { `/bin/rm -f /tmp/sperl$$ /tmp/sperl2$$`; die $_[0]; } sub make_filehandle { $fname = $_ = $_[0]; s/[^a-zA-Z]/_/g; s/^_*//; if (/^([a-z])([a-z]*)$/) { $first = $1; $rest = $2; $first =~ y/a-z/A-Z/; $_ = $first . $rest; } if (!$seen{$_}) { $opens .= "open($_,'>$fname') || die \"Can't create $fname.\";\n"; } $seen{$_} = $_; } sub make_label { $label = $_[0]; $label =~ s/[^a-zA-Z0-9]/_/g; if ($label =~ /^[0-9_]/) { $label = 'L' . $label; } $label = substr($label,0,8); if ($label =~ /^([a-z])([a-z]*)$/) { $first = $1; $rest = $2; $first =~ y/a-z/A-Z/; $label = $first . $rest; } $label; } sub transmogrify { { # case if (/^d/) { $dseen++; $_ = ' <<--#ifdef PRINTIT $printit = \'\'; <<--#endif next line;'; next; } if (/^n/) { $_ = '<<--#ifdef PRINTIT <<--#ifdef DSEEN <<--#ifdef ASSUMEP print if $printit++; <<--#else if ($printit) { print;} else { $printit++ unless $nflag; } <<--#endif <<--#else print if $printit; <<--#endif <<--#else print; <<--#endif <<--#ifdef APPENDSEEN if ($atext) {print $atext; $atext = \'\';} <<--#endif $_ = <>; <<--#ifdef TSEEN $tflag = \'\'; <<--#endif'; next; } if (/^a/) { $appendseen++; $command = $space . '$atext .=' . "\n<<--'"; $lastline = 0; while (<>) { s/^[ \t]*//; s/^[\\]//; unless (s|\\$||) { $lastline = 1;} s/'/\\'/g; s/^([ \t]*\n)/<><>$1/; $command .= $_; $command .= '<<--'; last if $lastline; } $_ = $command . "';"; last; } if (/^[ic]/) { if (/^c/) { $change = 1; } $addr1 = '$iter = (' . $addr1 . ')'; $command = $space . 'if ($iter == 1) { print' . "\n<<--'"; $lastline = 0; while (<>) { s/^[ \t]*//; s/^[\\]//; unless (s/\\$//) { $lastline = 1;} s/'/\\'/g; s/^([ \t]*\n)/<><>$1/; $command .= $_; $command .= '<<--'; last if $lastline; } $_ = $command . "';}"; if ($change) { $dseen++; $change = "$_\n"; $_ = " <<--#ifdef PRINTIT $space\$printit = ''; <<--#endif ${space}next line;"; } last; } if (/^s/) { $delim = substr($_,1,1); $len = length($_); $repl = $end = 0; for ($i = 2; $i < $len; $i++) { $c = substr($_,$i,1); if ($c eq '\\') { $i++; if ($i >= $len) { $_ .= 'n'; $_ .= <>; $len = length($_); $_ = substr($_,0,--$len); } elsif (!$repl && index("(|)",substr($_,$i,1)) >= 0) { $i--; $len--; $_ = substr($_,0,$i) . substr($_,$i+1,10000); } } elsif ($c eq $delim) { if ($repl) { $end = $i; last; } else { $repl = $i; } } elsif (!$repl && index("(|)",$c) >= 0) { $_ = substr($_,0,$i) . '\\' . substr($_,$i,10000); $i++; $len++; } } print "repl $repl end $end $_\n"; do Die("Malformed substitution at line $.") unless $end; $pat = substr($_, 0, $repl + 1); $repl = substr($_, $repl + 1, $end - $repl - 1); $end = substr($_, $end + 1, 1000); $dol = '$'; $repl =~ s'&'$&'g; $repl =~ s/[\\]([0-9])/$dol$1/g; $subst = "$pat$repl$delim"; $cmd = ''; while ($end) { if ($end =~ s/^g//) { $subst .= 'g'; next; } if ($end =~ s/^p//) { $cmd .= ' && (print)'; next; } if ($end =~ s/^w[ \t]*//) { $fh = do make_filehandle($end); $cmd .= " && (print $fh \$_)"; $end = ''; next; } do Die("Unrecognized substitution command ($end) at line $."); } $_ = $subst . $cmd . ';'; next; } if (/^p/) { $_ = 'print;'; next; } if (/^w/) { s/^w[ \t]*//; $fh = do make_filehandle($_); $_ = "print $fh \$_;"; next; } if (/^r/) { $appendseen++; s/^r[ \t]*//; $file = $_; $_ = "\$atext .= `cat $file 2>/dev/null`;"; next; } if (/^P/) { $_ = 'if (/(^[^\n]*\n)/) { print $1; }'; next; } if (/^D/) { $_ = 's/^[^\n]*\n//; if ($_) {redo line;} next line;'; next; } if (/^N/) { $_ = ' $_ .= <>; <<--#ifdef TSEEN $tflag = \'\'; <<--#endif'; next; } if (/^h/) { $_ = '$hold = $_;'; next; } if (/^H/) { $_ = '$hold .= $_ ? $_ : "\n";'; next; } if (/^g/) { $_ = '$_ = $hold;'; next; } if (/^G/) { $_ = '$_ .= $hold ? $hold : "\n";'; next; } if (/^x/) { $_ = '($_, $hold) = ($hold, $_);'; next; } if (/^b$/) { $_ = 'next line;'; next; } if (/^b/) { s/^b[ \t]*//; $lab = do make_label($_); if ($lab eq $toplabel) { $_ = 'redo line;'; } else { $_ = "goto $lab;"; } next; } if (/^t$/) { $_ = 'next line if $tflag;'; $tseen++; next; } if (/^t/) { s/^t[ \t]*//; $lab = do make_label($_); if ($lab eq $toplabel) { $_ = 'if ($tflag) {$tflag = \'\'; redo line;}'; } else { $_ = "if (\$tflag) {\$tflag = ''; goto $lab;}"; } $tseen++; next; } if (/^=/) { $_ = 'print "$.\n";'; next; } if (/^q/) { $_ = 'close(ARGV); @ARGV = (); next line;'; next; } } continue { if ($space) { s/^/$space/; s/(\n)(.)/$1$space$2/g; } last; } $_; }