Nach verschiedenen Quellen (zB href="http://www.se-radio.net/2008/03/episode-91-kevlin-henney-on-c/"> , wenn ich richtig), „C mit Klassen“ mit Prä-Prozessor-Technologie (mit dem Ausgang implementiert erinnern dann an einen C-Compiler zugeführt wird), während C ++ hat immer mit einem Compiler umgesetzt worden (das gerade passiert ist in den frühen Tagen C ausspucken). Das scheint Verwirrung zu stiften, also habe ich mich gefragt:
Wo genau ist die Grenze zwischen einem Präprozessor und einem Compiler? Wann rufen Sie ein Stück Software, die eine Sprache „einen Präprozessor“ implementiert, und wenn nennt man es „ein Compiler“?
Übrigens ist "eine kompilierte Sprache" ein etablierter Begriff? Wenn ja, was genau bedeutet das?
Das ist eine interessante Frage. Ich weiß keine definitive Antwort, aber würde das sagen, wenn man nach einem drängt:
Ein Präprozessor analysiert den Code nicht, sondern sucht stattdessen nach eingebetteten Mustern und erweitert sie um
Ein Compiler analysiert den Code tatsächlich, indem er einen AST (abstrakten Syntaxbaum) erstellt und diesen dann in eine andere Sprache umwandelt
Aus einer vereinfachten, persönlichen Sichtweise:
Ich betrachte den Präprozessor als eine beliebige Form der Textmanipulation, die keine Konzepte der zugrunde liegenden Sprache (dh Semantik oder Konstrukte) hat und daher nur auf eigenen Regeln beruht, um ihre Aufgaben zu erfüllen.
Der Compiler startet, wenn Regeln und Regeln auf das angewendet werden, was gerade verarbeitet wird (ja, macht 'meinen' Präprozessor zu einem Compiler, aber warum nicht: P), dazu gehören die synantische und lexikalische Überprüfung und die enthaltenen Transformationen von x ( textuell) zu y (binäre / Zwischenform). wie einer meiner Professoren sagen würde: "Es ist ein System mit Inputs, Prozessen und Outputs".
Der C / C ++ -Compiler kümmert sich um Typkorrektheit , während der Präprozessor Symbole einfach erweitert.
Ein Compiler besteht aus Serval-Prozessen (Komponenten). Der Präprozessor ist nur einer dieser und relativ einfachsten.
Aus dem Wikipedia-Artikel Aufteilung der Compiler-Prozesse :
Alle außer den kleinsten Compilern haben mehr als zwei Phasen. Jedoch, Diese Phasen werden üblicherweise als Teil des Frontends oder als das hintere Ende. Der Punkt, an dem sich diese beiden Enden treffen, ist offen für Debatte.
Das Frontend wird allgemein als syntaktisch angesehen und die semantische Verarbeitung findet statt, zusammen mit der Übersetzung in eine niedrigere Darstellungsstufe (als Quellcode).
Das mittlere Ende ist normalerweise Entwickelt, um Optimierungen in einem anderen Formular als dem Quellcode durchzuführen oder Maschinencode. Diese Quellcode / Maschinencode-Unabhängigkeit ist soll ermöglichen, generische Optimierungen zwischen Versionen zu teilen des Compilers unterstützt verschiedene Sprachen und Zielprozessoren.
Das Backend nimmt den Ausgang von der Mitte. Es kann mehr leisten Analyse, Transformationen und Optimierungen für eine bestimmte Computer. Dann erzeugt es Code für einen bestimmten Prozessor und ein bestimmtes Betriebssystem. "
Die Vorverarbeitung ist nur der kleine Teil des Front-End-Jobs.
Der erste C ++ - Compiler, der durch Anfügen eines zusätzlichen Prozesses vor dem vorhandenen C-Compiler-Toolset erstellt wurde, nicht weil es ein gutes Design ist, sondern weil Zeit und Ressourcen begrenzt sind.
Heutzutage glaube ich nicht, dass ein solcher nicht-nativer C ++ - Compiler im kommerziellen Bereich überleben kann.
Die Antwort ist ziemlich einfach. Ein Präprozessor arbeitet an Text als Eingabe und hat Text als Ausgabe. Beispiele hierfür sind die alten Unix-Befehle m4, cpp (der C-Pre-Prozessor), sowie Unix-Programme wie roff und nroff und troff, die man-Seiten (Unix-Kommando "man") formatieren (oder formatieren) oder formatieren zum Drucken oder Setzen. Präprozessoren sind sehr einfach, sie wissen nichts über die "Sprache des Textes", die sie verarbeiten. Mit anderen Worten, sie verarbeiten normalerweise natürliche Sprachen. Der C-Präprozessor neben seinem Namen, z.B. erkennt nur #define, #include, #ifdef, #ifndef, #else usw. und wenn Sie #define MACRO verwenden, versucht es das Makro überall dort zu "erweitern", wo es es findet. Aber das muss kein C- oder C ++ - Programmtext sein, es kann auch ein Roman auf Italienisch oder Griechisch sein. Compiler, die sich in eine andere Sprache übersetzen, werden normalerweise als Übersetzer bezeichnet. So war der alte cfront "Compiler" für C ++, der C-Code ausgab, ein C ++ - Übersetzer. Präprozessoren und spätere Übersetzer werden historisch verwendet, weil alten Maschinen einfach nicht genügend Speicher zur Verfügung stand, um alles in einem Programm ausführen zu können, sondern stattdessen von spezialisierten Programmen und von Platte zu Platte. Ein typisches C-Programm würde aus verschiedenen Quellen zusammengestellt werden. Und der Build-Prozess würde mit make verwaltet werden. In unseren Tagen wird der C-Präprozessor normalerweise direkt in den C / C ++ - Compiler eingebaut. Ein typischer make-Lauf würde den CPP auf den * .c-Dateien aufrufen und die Ausgabe in ein anderes Verzeichnis schreiben, von dort würde entweder der C-Compiler CC ihn direkt in Maschinencode kompilieren oder allgemeiner Assemblercode als Text ausgeben. Hinweis: Der c-Compiler überprüft nur die Syntax, es kümmert sich nicht wirklich um die Typensicherheit usw. Dann würde der Assembler diesen Assembler-Code nehmen und eine * .o-Datei ausgeben, die später mit anderen * .o-Dateien und * .lib verknüpft werden kann Dateien in ein ausführbares Programm. OTOH Sie hatten wahrscheinlich eine make-Regel, die nicht den C-Compiler aufrufen würde, sondern den lint-Befehl, den C-Sprachanalysator, der nach typischen Fehlern und Fehlern sucht (die vom c-Compiler ignoriert werden). Es ist ziemlich interessant, in Wikipedia nach Flusen, Nroff, Troff, M4 usw. zu suchen (D oder D)
Tags und Links c++ compiler-construction terminology preprocessor