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 false
scheint 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.
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:
Da dies mein Werkzeug ist, nehmen Sie dies nicht als "Empfehlung". Ich berichte lediglich von seiner Existenz.
Mawg sagt, Monica wieder einzusetzen