2

Is there any tool available that will strip optional braces from code written in curly-brace programming languages?

Without starting a flame war, I'd like to follow the K&R style, where braces only appear where necessary. Artistic Style (astyle) allows me to automatically strip braces from single line statements, so

if (something) {
    do_something();
}

becomes

if (something)
    do_something();

using the --remove-brackets (-xj) command. However, astyle cannot handle the case of

for (int i = 0; i < 5; i++) {
    if (x == y) {
        q();
    } else if (x > y) {
        w();
    } else {
        r();
    }
}

and converts it to

for (int i = 0; i < 5; i++) {
    if (x == y)
        q();
    else if (x > y)
        w();
    else
        r();
}

where the for loop's braces are not stripped, even though they can be.

It looks as though clang-format has BraceWrapping settings, but setting all these to false doesn't seem to have any effect for when I run clang-format on the file.

Edit: Eclipse's CDT was able to do this and I'm looking for a tool that doesn't require Eclipse to be installed.

  • If you don that, you'll regret it. Maybe not today, maybe not tomorrow, but soon and for the rest of your life (with apologies to Bogie) – Mawg Aug 4 '16 at 11:56
1

Our DMS Software Reengineering Toolkit can do this.

DMS is a program transformation system that parses source text to compiler data structures, applies transformations on those data structures to produce essentially a different program, and then can regenerate source code for the modified program back from those data structures. DMS uses compiler-accurate front ends to do the parsing (and other analysis appropriate for the language). DMS has full, mature front ends for C and C++.

DMS transformations are usually written as source-to-transforms, that essential mean

if you see *this_pattern*, replace it by *that_pattern*

written in this format:

rule rulename( named_syntax_parameters ) : syntax_category -> syntax_category =
   " surface-syntax_pattern " -> " surface-syntax-replacement-pattern ";

The quote marks are not string quotes, but meta-quotes; they distinguish the syntax needed to express the rules from the syntax of the programming language you want to manipulate. For a more precise description, see the link.

For OP's problem, in about 10 minutes I defined a set of DMS rewrite rules for the GCC4 dialect of C:

default base domain C~GCC4;

rule remove_useless_bracket_anywhere(s: statement): statement -> statement
  = "  { \s } " ->  " \s " ;

public ruleset remove_useless_brackets_all = {
  remove_useless_bracket_anywhere 
};

rule remove_useless_brackets_for1( fisc: for_init_statement, c: condition,
               e:expression, s: statement): statement -> statement
  = "  for ( \fisc \c ; \e ) { \s } " ->  " for ( \fisc ; \e ) \s " ;

public ruleset remove_useless_brackets_for = {
  remove_useless_brackets_for1
};

pattern not_single_statement_block(s: statement): statement
  = s if ~[s2:statement. s <: "\:compound_statement { \s2 }"];

rule remove_useless_bracket_while( e: expression, s: statement): statement -> statement
  = "  while (\e) { \s } " ->  " while (\e) \s " ;

rule remove_useless_bracket_if_then( e: expression, s: statement): statement -> statement
  = "  if (\e) { \s } " ->  " if (\e) \s " ;

rule remove_useless_bracket_if_then_else( e: expression, s1: statement, s2: statement ): statement -> statement
  = "  if (\e) { \s1 } else { \s2 } " ->  " if (\e) \s1 else \s2 " ;

rule remove_useless_bracket_if_then_statement_else_compound_statement( e: expression,
    s: statement, nssb: statement ): statement -> statement
  = "  if (\e) { \s } else \not_single_statement_block\(\nssb\) " ->  " if (\e) \s else \nssb " ;

rule remove_useless_bracket_if_then_compound_statement_else_statement( e: expression,
    s: statement, nssb: statement ): statement -> statement
  = "  if (\e) \not_single_statement_block\(\nssb\) else { \s } " ->  " if (\e) \nssb else \s " ;

public ruleset remove_useless_brackets_not_for = {
   remove_useless_bracket_while,
   remove_useless_bracket_if_then,
   remove_useless_bracket_if_then_else,
   remove_useless_bracket_if_then_statement_else_compound_statement,
   remove_useless_bracket_if_then_compound_statement_else_statement
};

You can see individual rules that express C surface syntax with named parameters n:" in the rule parameter lists and named \n embedded inside the metaquotes for the patterns.

Each individual rule handles transforming a C control construct; there are ones for for statements, while loops, and if statements. The reason for multiple if-statement rules is to handle the combinations. I broke them up this way because OP want to remove { ... } from all constructs except for statements.

There are rulesets which collect a set of rules; that makes it easy to invoke a set of rules to achieve a purpose.

The pattern construct named not_single_statement_block is used by some of the rules to detect blocks that don't contain single statements.

For an example, I turned OP's code fragment into a full program in a trivial way:

void main() {

for (int i = 0; i < 5; i++) {
    if (x == y) {
        q();
    } else if (x > y) {
        w();
    } else {
        r();
    }
    }

}

If we run a DMS-generated C transformer tool on this example using the most general brace-removing ruleset remove_useless_brackets_all we get:

C:\DMS\Domains\C\GCC4\Tools\RuleApplier\Source>run ..\DomainRuleApplier.P0B C:\temp\brackets.c Tools/RuleApplier/eliminate_useless_b
rackets/remove_useless_brackets_all
Domain RuleApplier 1.5.0
Parsing "C:\temp\brackets.c"
Done Parsing file
Registry: Loading RSL definitions from "C:/DMS/Domains/C/GCC4/Tools/RuleApplier/eliminate_useless_brackets.rsl" ...
Registry: Successfully loaded RSL definitions from "C:/DMS/Domains/C/GCC4/Tools/RuleApplier/eliminate_useless_brackets.rsl".

void main() {

for (int i = 0
 ;          i < 5; i++)
if (x == y)
    q();
else   if (x > y)
    w();
       else
    r();
    }

You can see this removes all the single-statement block including the one of the for statement. OP didn't want that.

So we run instead using the remove_useless_brackets_not_for ruleset, and obtain:

C:\DMS\Domains\C\GCC4\Tools\RuleApplier\Source>run ..\DomainRuleApplier.P0B C:\temp\brackets.c Tools/RuleApplier/eliminate_useless_brackets/remove_useless_brackets_not_for
Domain RuleApplier 1.5.0
Parsing "C:\temp\brackets.c"
Done Parsing file
Registry: Loading RSL definitions from "C:/DMS/Domains/C/GCC4/Tools/RuleApplier/eliminate_useless_brackets.rsl" ...
Registry: Successfully loaded RSL definitions from "C:/DMS/Domains/C/GCC4/Tools/RuleApplier/eliminate_useless_brackets.rsl".

void main() {

for (int i = 0
 ;          i < 5; i++) {
if (x == y)
    q();
else   if (x > y)
    w();
       else
    r();
            }
    }

This is what OP shows in his example as the desired result.

The output formatting for these results admittedly look funny. That's because the toy tool I built to do this is "prettyprinting" in "preserve" mode; it is trying to preserve the orginal columns where it can; where it can't preserve a column number it either inserts a line break or adds spaces to get to the next token's target column. In a big program with a small number of transforms actually applied, this is what you want, if you want the program to look mostly untouched. Or, you can configure DMS to prettyprint the text and ignore the original column numbers; then everything lines up nicely but that example isn't here.

OK, so regarding OP's request:

  • DMS is a a tool that will strip optional braces from code written in curly-brace programming languages using rewrite rules
  • Can handle many languages (specifically to OP's explicit tags, C and C++)
  • Runs under Windows (or Linux with Wine)
  • Doesn't require Eclipse to be installed (regarding OP's original intent , DMS is a pretty big system; you have to install it instead, and that IMHO probably isn't worth the trouble for this specific problem)
  • Commercially available

Since this is my tool, don't take this as a "recommendation". I'm merely reporting its existence.

  • Thanks. This was rally helpful. Thanks for the lengthy and very detailed response. – lissachen Jul 15 '16 at 23:22
  • 1
    If you like the answer, you can upvote it. Click the ^ at top-left of the answer. – Ira Baxter Jul 15 '16 at 23:45
  • Ira, I can't find the price on the site - did I miss it? – Mawg Aug 4 '16 at 11:59
  • @Mawg: No, you didn't. DMS is an enterprise product. Price varies depending on components you acquire and deployment models. Contact the site to ask for details. – Ira Baxter Aug 4 '16 at 13:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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