Note that there are some explanatory texts on larger screens.

plurals
  1. POhow to separate stuff I want from what I don't in perl?
    text
    copied!<p>I have to apply transformations on code C++ code, but not comments or preprocessor statements. It's the preprocessor statements that I'm having trouble with. Basically, I want something like this:</p> <pre><code>#!/usr/bin/perl my $file = $ARGV[0]; my $doubleQuotedString = q{"(?&gt;[^"\\\\]++|\\\\{2}|\\\\(?s).)*+"}; my $singleQuotedString = q{'(?&gt;[^'\\\\]++|\\\\{2}|\\\\(?s).)*+'}; my ($rest, $code, $stuffToIgnore) = (""); open(my $inputFH, "&lt;:raw:crlf", $file) or die "can't open $file for reading. $!"; open(my $outputFH, "&gt;:raw:crlf", "$file.out") or die "can't open $file.out for writing. $!"; my $counter = 0; while (&lt;$inputFH&gt;) { $_ = "$rest$_"; do { ($code, $stuffToIgnore, $rest) = m( ((?: $doubleQuotedString # found a string |$singleQuotedString # found a string |(?:[^/]++|/[^*/]) # found something not a string, comment or preprocessor statement )*+ ) ((?: ^\s*+#.*$ | # preprocessor statement \s*+//.*$ | # line comment \s*+/\*(?:[^*]++|\*(?!/))*+\*/ # block comment )*+ ) ((?s).*) # rest )xm; ++$counter; goto BLOCK_READ if $stuffToIgnore ne "" or eof($inputFH); } while ($_ .= &lt;$inputFH&gt;); BLOCK_READ: defined $code or die "Unterminated block."; # do transformation on $code print "CODE: &gt;&gt;$code&lt;&lt;\nIGNORE: &gt;&gt;$stuffToIgnore&lt;&lt;\n"; print $outputFH "$code$stuffToIgnore"; } </code></pre> <p>My problem is the one commented as <code># found something not a string, comment or preprocessor statement</code>. Commenting out the line <code># preprocessor statement</code> make it work for, but it will consider preprocessor statements as code to apply the transformation on.</p> <p>How can I change the first part of the regex to fail on a preprocessor statement? Or maybe you have another way of doing this?</p> <p><strong>EDIT</strong></p> <p>I finished the answer given @sln's help. I'm posting it here as a reference at to how I accomplished what I was attempting to do while also leaving in some debugging stuff for those who are interested.</p> <pre><code>#!/usr/bin/perl use strict; use warnings; my $file = $ARGV[0]; my $debug = 1; my ($rest, $code, $ignore) = (""); my $lineNumber = 1; my $topLineOfBlock; open(my $inputFH, "&lt;:raw:crlf", $file) or die "can't open $file for reading. $!"; open(my $outputFH, "&gt;:raw:crlf", "$file.out") or die "can't open $file.out for writing. $!"; my $complete = 1; # NOTE: These 2 must be declared in the base scope of the package. my $lineOffset; # See https://rt.perl.org/Ticket/Display.html?id=120554 for details. while ($_ = &lt;$inputFH&gt;, !eof($inputFH) or length($rest) != 0) { $topLineOfBlock = $lineNumber; print "Read line $lineNumber\n" if $debug; if (defined $_) { $_ = "$rest$_"; } else { $_ = $rest; } my $loopAgain; do { if (/\\$/) # if line ends with '\' read and append in next line { $complete = 0; } elsif (eof($inputFH) or /;\s*+$/) # if eof or line does end in a ';', break it up. # otherwise read and append in next line. { print "INPUT: '$_'\n" if $debug; use re 'eval'; m% (?{print "STRING: '${^POSTMATCH}'\n" if $debug}) (?{$lineOffset = 0}) # ROUTINES (?!) # Ignore this section for matching # DEBUG ROUTINES # Call them using (?N) where N is the corrisponding number. ((?{print "1]'${^MATCH}'\n" if $debug})) ((?{print "2]'${^MATCH}'\n" if $debug})) ((?{print "3]'${^MATCH}'\n" if $debug})) ((?{print "4]'${^MATCH}'\n" if $debug})) ((?{print "5]'${^MATCH}'\n" if $debug})) ((?{print "6]'${^MATCH}'\n" if $debug})) ((?{print "7]'${^MATCH}'\n" if $debug})) ((?{print "8]'${^MATCH}'\n" if $debug})) ((?{print "9]'${^MATCH}'\n" if $debug})) ((?{print "10]'${^MATCH}'\n" if $debug})) ((?{print "11]'${^MATCH}'\n" if $debug})) ((?{print "12]'${^MATCH}'\n" if $debug})) ((?{print "13]'${^MATCH}'\n" if $debug})) ((?{print "14]'${^MATCH}'\n" if $debug})) ((?{print "15]'${^MATCH}'\n" if $debug})) ((?{print "16]'${^MATCH}'\n" if $debug})) ((?{print "17]'${^MATCH}'\n" if $debug})) ((?{print "18]'${^MATCH}'\n" if $debug})) ((?{print "19]'${^MATCH}'\n" if $debug})) # SUBROUTINES # States that code read in is in an incomplete state. (?&lt;INCOMPLETE&gt;(?{print "INCOMPLETE: '${^MATCH}'\n" if $debug; $complete = 0;})) # States that code read in is in a completed state. (?&lt;COMPLETE&gt; (?{print "COMPLETE: '${^MATCH}'\n" if $debug; $complete = 1;})) # Matches against one character that has been escaped including EOL. # If a quoted EOL found, mark match as incomplete. (?&lt;ESCAPED_CHAR&gt; \\ (?: (?&amp;EOL) (?&amp;INCOMPLETE) | (?s). ) ) # Matches against a single quoted string excluding EOL. (?&lt;SINGLE_QUOTED_STRING&gt; \'(?&amp;INCOMPLETE) # Escaped quotes due to a syntax highlighting bug in SO (?: [^\'\\\\n]++ # Escaped quotes due to a syntax highlighting bug in SO | (?&amp;ESCAPED_CHAR) )*+ \'(?&amp;COMPLETE) # Escaped quotes due to a syntax highlighting bug in SO ) # Matches against a double quoted string excluding EOL. (?&lt;DOUBLE_QUOTED_STRING&gt; \"(?&amp;INCOMPLETE) # Escaped quotes due to a syntax highlighting bug in SO (?: [^\"\\\n]++ # Escaped quotes due to a syntax highlighting bug in SO | (?&amp;ESCAPED_CHAR) )*+ \"(?&amp;COMPLETE) # Escaped quotes due to a syntax highlighting bug in SO ) # matches strings intermingled with other chars excluding EOL. (?&lt;STRINGS_WITH_CHARS&gt; (?: # (?&amp;NON_ESCAPED_CHARS) [^\\\n\"\']++ # Escaped quotes due to a syntax highlighting bug in SO | (?&amp;DOUBLE_QUOTED_STRING) | (?&amp;SINGLE_QUOTED_STRING) | (?&amp;ESCAPED_CHAR) )*+ ) # Matches against non escaped characters excluding EOL. (?&lt;NON_ESCAPED_CHARS&gt; [^\\\n]++) # Matches all non escaped chars and escaped chars. # upto but not including the EOL unless it's escaped. (?&lt;CHARS&gt; (?:(?&amp;NON_ESCAPED_CHARS)|(?&amp;ESCAPED_CHAR))*+) # Matches EOL (end of line) or EOS (end of string) and states it is in a complete state. (?&lt;EOL_OR_EOS&gt; (?&amp;EOL) | $ (?&amp;COMPLETE)) # Matches on EOL and increments $lineOffset if matched. # When using this, make sure you don't allow backtracking over this call. (?&lt;EOL&gt; \n(?{++$lineOffset})) | # ACTUAL SEARCH (?&lt;ignore&gt; (?: (?&amp;EOL)? ^ [^\S\n]*+ \# (?&amp;STRINGS_WITH_CHARS) (?&amp;EOL_OR_EOS) # preprocessor statement # Escaping slashes due to a syntax highlighting bug in SO | \s*+ \/\/ (?&amp;CHARS) (?&amp;EOL_OR_EOS) # line comment | \s*+ \/\* (?&amp;INCOMPLETE) # block comment (?: [^*]++ | \* (?!\/) )*+ \*\/ (?&amp;COMPLETE) # block comment completed )*+ ) (?(?{$complete}) # completed parse of all ignored stuff? Then read code stuff. (?&lt;code&gt; (?: (?!^[^\S\n]*+\#) # do not match on a preprocessor statement (?: (?&amp;DOUBLE_QUOTED_STRING) # found a string | (?&amp;SINGLE_QUOTED_STRING) # found a string | (?: [^\'\"/\n]++ | /[^*/\n]) # found something not a string or comment or newline # Escaped quotes due to a syntax highlighting bug in SO | (?&amp;EOL) # newline ) )*+ ) (?&lt;rest&gt; (?s).* # match to the end of the string ) ) # if not completed, read in more stuff and do parse over again. %xmp; ($code, $ignore, $rest) = ($+{'code'}, $+{'ignore'}, $+{'rest'}); print "**COMPLETE = $complete\n" if $debug; goto BLOCK_READ_COMPLETE if $complete or eof($inputFH); } # read in more data to allow for a complete parse ++$lineNumber; print "Reading line $lineNumber\n" if $debug; my $newStuff = &lt;$inputFH&gt;; if (defined $newStuff) { $_ .= $newStuff; $loopAgain = 1; } else { $loopAgain = 0; } } while ($loopAgain); BLOCK_READ_COMPLETE: $complete or die "Something wasn't terminated at line ". ($topLineOfBlock+$lineOffset) ." of file '$file'.\n"; # do transformation on $code print "CODE: &gt;&gt;$code&lt;&lt;\nIGNORE: &gt;&gt;$ignore&lt;&lt;\nREST: &gt;&gt;$rest&lt;&lt;\n" if $debug; print $outputFH "$ignore$code"; } </code></pre> <p>To see a working demo, see <a href="http://ideone.com/mDN2kj" rel="nofollow">here</a>.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload