3
\$\begingroup\$

This question is the real question asked on StackOverflow. I'm here to review my answer and see how can I optimize it.


Here is the answer text:

This is a basic approach, but it proposes a proof of concept of what might be done. I do it using Bash along with the usage of the GCC -fsyntax-only option.

Here is the bash script:

#!/bin/bash
while IFS='' read -r line || [[ -n "$line" ]]; do
    LINE=`echo $line | grep -oP "(?<=//).*"`
    if [[ -n "$LINE" ]]; then
            echo $LINE | gcc -fsyntax-only -xc -
            if [[ $? -eq 0 ]]; then
                   sed -i "/$LINE/d" ./$1
            fi
    fi
done < "$1"

The approach I followed here was reading each line from the code file. Then, greping the text after the // delimiter (if exists) with the regex (?<=//).* and passing that to the gcc -fsyntax-only command to check whether it's a correct C/C++ statement or not. Notice that I've used the argument -xc - to pass the input to GCC from stdin (see my answer here to understand more). An important note, the c in -xc - specifies the language, which is C in this case, if you want it to be C++ you shall change it to -xc++.

Then, if GCC was able to successfully parse the statement (i.e., it's a legitimate C/C++ statement), I directly remove it using sed -i from the file passed.


Running it on your example (but after removing <- commented code from the third line to make it a legitimate statement):

// Those parameters control foo and bar... <- valid comment
int t = 5;
// int t = 10;
int k = 2*t;

Output (in the same file):

// Those parameters control foo and bar... <- valid comment
int t = 5;
int k = 2*t;

(if you want to add your modifications in a different file, just remove the -i from sed -i)

The script can be called just like: ./script.sh file.cpp, it may show several GCC errors while these are the correct

New contributor
Andrew Naguib is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
\$\endgroup\$
3
\$\begingroup\$
  • echo | grep is unwarranted. bash understands regular expressions ("$line" =~ regex), and can do simple substitutions: line=${line#[[:space:]]*\/\/} removes leading whitespaces , followed by the comment, just what we are after.

  • Replacing the file while reading it looks suspiciously. I recommend to have a destination file, and copy valid lines (and don't copy undesired ones). A perk benefit is that forking sed is not needed anymore.

A side note: the script makes a false positive in cases like

    // Notice that
    // some_valid_c_code;
    // doesn't work, because etc

The part of the comment would be recognized as a dead code, and the output will be

    // Notice that
    // doesn't work, because etc
\$\endgroup\$
  • \$\begingroup\$ Your side note, you mean the code is going to remove all of the comments? \$\endgroup\$ – Andrew Naguib Jan 11 at 20:40
  • \$\begingroup\$ @AndrewNaguib No. See edit \$\endgroup\$ – vnp Jan 11 at 20:41
  • \$\begingroup\$ Yeah, true. But, who would write a comment in such a way (i.e., "some_valid_c_code;"? :) \$\endgroup\$ – Andrew Naguib Jan 11 at 20:42
  • 1
    \$\begingroup\$ @AndrewNaguib Me, for starters. And I've seen it in the wild. That is quite a good way to explain some not-so-obvious design decisions. \$\endgroup\$ – vnp Jan 11 at 20:47
  • 1
    \$\begingroup\$ @AndrewNaguib Thanks for pointing the typo; fixed. The operator returns 0 or 1 depending on match success or failure. Use it in if [[ "$line" =~ regex]]. \$\endgroup\$ – vnp Jan 11 at 21:12

Your Answer

Andrew Naguib is a new contributor. Be nice, and check out our Code of Conduct.

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.