Das Unternehmen, für das ich arbeite, Semantic Designs Inc., bietet Werkzeuge an, die eine allgemeine Infrastruktur für die Analyse und Transformation von Programmen und spezifische Analysekomponenten für verschiedene Programmiersprachen. Zusammen sind sie als DMS bekannt. Im Fall von C++ umfasst DMS integrierte Lexer, Präprozessoren, Parser, Namen und Typen Auflösungskomponenten für GCC3, GCC4, ISO14882c1998 (ANSI), Visual C++ 6.0 und unverwaltetes Visual Studio 2005 C++. Für verschiedene Dialekte von C gibt es auch eine Kontrollflussanalyse, einen Side Effects Analysator und einen Symbolabhängigkeitsanalysator, mit dem Werkzeuge wie ein Zeigerprüfer, Entferner von deaktivem Code, Funktionsprofiler und Programm Slicer implementiert wurden.
Die Komponenten zur Namens- und Typauflösung liefern eine vollständige Symboltabelle Informationen und Nachschlagemöglichkeiten, so dass Verweise auf Identifikatoren leicht mit ihren Typen und anderen deklarativen deklarativen Informationen. Die Informationen sind wie die erfassten und von einem Compiler verwendet werden, werden aber zusammen mit abstrakten Syntaxbäumen in einer Form aufbewahrt, die eine adaptive Wiederverwendung durch jedes Werkzeug ermöglicht, das die Komponente.
Semantic Designs hat kürzlich ein maßgeschneidertes Tool entwickelt, das speziell auf die Typen von Indexvariablen in Schleifendeklarationen Deklarationen, wie in Ihrem Beispiel. In diesem Fall bestand das Problem darin GCC2-Code zu aktualisieren, der den Compilerschalter -fno-for-scope verwendet, der eine Auflösungsregel für Schleifenvariablen vorsah, die nicht in späteren GCC-Dialekten nicht unterstützt wurde. Das Werkzeug musste die Schleifen transformieren, die Deklarationen ihrer Schleifenvariablen in einen äußeren Kontext verschieben der die -fno-for-scope Scoping-Regel beibehielt. Wo solche Änderungen nicht notwendig waren, wurde keine Änderung vorgenommen.
Das Tool musste also den mit jeder Referenz verbundenen Typ erkennen auf eine Schleifenvariable, wobei im Falle von Maskierungsbereichen zu unterscheiden ist, und den Code so rekonstruieren, dass die GCC3- und GCC4-Namensauflösung Namensauflösung zur gleichen semantischen Interpretation führt wie beim GCC2 mit -fno-for-scope. Dies erforderte die Möglichkeit, auf die Symboltabelle Informationen zugreifen zu können, die mit jeder Variablenreferenz verbunden sind, und in dem Fall wo Code verschoben wurde, die korrekte syntaktische Form der Typdeklaration für jede Variable zu rekonstruieren, deren der Typdeklaration für jede Variable, deren Deklaration verschoben wurde, zu rekonstruieren. Die Symboltabelle und die Bezeichnerreferenztabelle, die von der DMS C++-Namens- und Typauflösungskomponente bereitgestellte Symboltabelle und Bezeichnerreferenztabelle enthielt alle erforderlichen Informationen, und ein Modul zur Rekonstruktion der vorgeschriebenen Typsyntax ermöglichte die Synthese von korrekten neuen Typdeklarationen.
Betrachten Sie zum Beispiel das folgende Beispiel:
// loop variable hides variable in global scope
// will change meaning without -fno-for-scope
// fix: move decl. of cnt before for-loop
// optionally rename globcnt loop variable
float globcnt = 0.0;
int Foo::foo3() {
for (int globcnt = 0; globcnt < 5; globcnt++) {
globalInt += globcnt;
}
globalInt += 2*globcnt + 1;
return 0;
}
Die GCC2 -fno-for-scope Semantik zeigt an, dass die Referenzen auf globcnt außerhalb der Schleife auf die Schleifenvariable verweisen, auch wenn GCC3 die Schleifenvariable als "out of scope" betrachtet und die Verweise auf die die globale Variable auflöst. Das Tool wandelte diesen Code in:
float globcnt = 0.0;
int Foo::foo3() {
int globcnt = 0;
for (; globcnt < 5; globcnt++) {
globalInt += globcnt;
}
globalInt += 2*globcnt + 1;
return 0;
}
Wäre der Code nicht transformiert worden, hätte der GCC4 immer ein Wert von 1 aus Foo:foo3 zurückgegeben. Transformiert wäre der Wert jedoch durch die Iterationen der Schleife beeinflusst worden, wie sie ursprünglich für GCC2. Das Werkzeug musste erkennen, dass der letzte Verweis auf globcnt auf die lokale Variable vom Typ int war, nicht auf die globale Variable vom Typ float war, was es über die Symboltabelle nachschlagen konnte, und es musste entsprechend handeln.
Andererseits hat das Tool im folgenden Code erkannt, dass dass es keine Verweise auf i außerhalb der Schleife gab, so dass es akzeptabel war (und vorzuziehen), die Deklaration der Schleifenvariablen intakt zu lassen.
int Foo::foo0() {
for (int i = 0; i < 10; i++) {
globalInt += i*i;
}
return 0;
}