Entfernen optionaler geschweifter Klammern im Code

Gibt es ein Tool, das optionale Klammern aus Code entfernt, der in Programmiersprachen mit geschweiften Klammern geschrieben wurde?

Ohne einen Flammenkrieg zu beginnen, möchte ich dem K&R-Stil folgen, bei dem Klammern nur dort erscheinen, wo es nötig ist. Artistic Style (astyle) ermöglicht es mir, Klammern automatisch aus einzeiligen Anweisungen zu entfernen, so

if (something) {
    do_something();
}

wird

if (something)
    do_something();

mit dem Befehl --remove-brackets (-xj). Astyle kann jedoch nicht mit dem Fall umgehen

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

und wandelt es um

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

wobei die geschweiften Klammern der for-Schleife nicht entfernt werden, obwohl sie es sein können.

Es sieht so aus, als ob Clang-Format BraceWrapping-Einstellungen hat, aber das Festlegen all dieser Einstellungen falsescheint keine Auswirkungen zu haben, wenn ich Clang-Format für die Datei ausführe.

Bearbeiten: Das CDT von Eclipse konnte dies tun, und ich suche nach einem Tool, für das Eclipse nicht installiert sein muss.

Wenn Sie das tun, werden Sie es bereuen. Vielleicht nicht heute, vielleicht nicht morgen, aber bald und für den Rest deines Lebens (mit Entschuldigung an Bogie)

Antworten (1)

Unser DMS Software Reengineering Toolkit kann dies leisten.

DMS ist ein Programmtransformationssystem , das Quelltext in Compiler-Datenstrukturen analysiert, Transformationen auf diese Datenstrukturen anwendet, um im Wesentlichen ein anderes Programm zu erzeugen, und dann den Quellcode für das modifizierte Programm aus diesen Datenstrukturen regenerieren kann. DMS verwendet Compiler-genaue Frontends , um das Parsing (und andere für die Sprache geeignete Analysen) durchzuführen. DMS verfügt über vollständige, ausgereifte Frontends für C und C++.

DMS-Transformationen werden normalerweise als Quelle-zu-Transformationen geschrieben, das heißt im Wesentlichen

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

in diesem Format geschrieben:

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

Die Anführungszeichen sind keine String-Anführungszeichen, sondern Meta-Anführungszeichen ; Sie unterscheiden die zum Ausdrücken der Regeln erforderliche Syntax von der Syntax der Programmiersprache, die Sie bearbeiten möchten. Eine genauere Beschreibung finden Sie unter dem Link.

Für das Problem von OP habe ich in etwa 10 Minuten eine Reihe von DMS-Umschreibungsregeln für den GCC4-Dialekt von C definiert:

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
};

Sie können einzelne Regeln sehen, die die C-Oberflächensyntax mit benannten Parametern n :" in den Regelparameterlisten und mit dem Namen \n ausdrücken, die in die Metaquotes für die Muster eingebettet sind.

Jede einzelne Regel behandelt die Transformation eines C-Kontrollkonstrukts; Es gibt For-Anweisungen, While-Schleifen und If-Anweisungen. Der Grund für mehrere if-Anweisungsregeln besteht darin, die Kombinationen zu handhaben. Ich habe sie auf diese Weise aufgelöst, weil OP { ... } aus allen Konstrukten außer Anweisungen entfernen möchte .

Es gibt Regelsätze , die einen Satz von Regeln sammeln; das macht es einfach, eine Reihe von Regeln aufzurufen, um einen Zweck zu erreichen.

Das Musterkonstrukt namens not_single_statement_block wird von einigen Regeln verwendet, um Blöcke zu erkennen, die keine einzelnen Anweisungen enthalten.

Als Beispiel habe ich das Codefragment von OP auf triviale Weise in ein vollständiges Programm umgewandelt:

void main() {

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

}

Wenn wir in diesem Beispiel ein DMS-generiertes C-Transformer-Tool mit dem allgemeinsten Regelsatz zum Entfernen von Klammern remove_useless_brackets_all ausführen, erhalten wir:

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();
    }

Sie können sehen, dass dadurch alle einzelnen Anweisungsblöcke einschließlich der for-Anweisung entfernt werden. OP wollte das nicht.

Also führen wir stattdessen den Regelsatz remove_useless_brackets_not_for aus und erhalten:

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();
            }
    }

Dies zeigt OP in seinem Beispiel als gewünschtes Ergebnis.

Die Ausgabeformatierung für diese Ergebnisse sieht zugegebenermaßen komisch aus. Das liegt daran, dass das Spielzeug-Tool, das ich dafür gebaut habe, "prettyprinting" im "preserve"-Modus ist; es versucht, die ursprünglichen Spalten zu bewahren, wo es möglich ist; wo es eine Spaltennummer nicht beibehalten kann, fügt es entweder einen Zeilenumbruch ein oder fügt Leerzeichen hinzu, um zur Zielspalte des nächsten Tokens zu gelangen. In einem großen Programm mit einer kleinen Anzahl von tatsächlich angewendeten Transformationen ist dies das, was Sie wollen, wenn Sie möchten, dass das Programm weitgehend unberührt aussieht. Oder Sie können DMS so konfigurieren, dass es den Text schön druckt und die ursprünglichen Spaltennummern ignoriert; dann passt alles gut zusammen, aber dieses Beispiel ist nicht hier.

OK, also bezüglich der Anfrage von OP:

  • DMS ist ein Tool, das optionale Klammern aus Code entfernt, der in Programmiersprachen mit geschweiften Klammern geschrieben wurde, indem es Umschreibregeln verwendet
  • Kann mit vielen Sprachen umgehen (insbesondere mit den expliziten Tags von OP, C und C++)
  • Läuft unter Windows (oder Linux mit Wine)
  • Eclipse muss nicht installiert werden (in Bezug auf die ursprüngliche Absicht von OP ist DMS ein ziemlich großes System; Sie müssen es stattdessen installieren, und das ist meiner Meinung nach die Mühe für dieses spezielle Problem wahrscheinlich nicht wert).
  • Im Handel erhältlich

Da dies mein Werkzeug ist, nehmen Sie dies nicht als "Empfehlung". Ich berichte lediglich von seiner Existenz.

Vielen Dank. Das war hilfreich. Danke für die lange und sehr ausführliche Antwort.
Ira, ich kann den Preis auf der Website nicht finden - habe ich ihn übersehen?
@Mawg: Nein, hast du nicht. DMS ist ein Unternehmensprodukt. Der Preis variiert je nach erworbenen Komponenten und Bereitstellungsmodellen. Wenden Sie sich an die Website, um Einzelheiten zu erfragen.