Je fais un simple compilateur pour une simple langue d'animal de compagnie que je crée et viennent d'un contexte C (bien que je l'écris dans Ruby) Je me demandais si un prétraiteur est nécessaire. P>
Que pensez-vous? Un préprocesseur "muet" est-il toujours nécessaire dans les langues modernes? Les capacités de compilation conditionnelle C # seraient-elles considérées comme un «préprocesseur»? Est-ce que chaque langue moderne n'inclut pas un préprocesseur a-t-elle des utilitaires nécessaires pour le remplacer correctement? (Par exemple, le préprocesseur C ++ est maintenant principalement obsolète (bien que tenté) à cause de modèles.) p>
9 Réponses :
Le préprocesseur est une méthode bon marché pour fournir des installations de métaprogramming incomplètes à une langue de manière laid. p>
Préférez la véritable métaprogrammation ou les macros de style LISP à la place. P>
Bien dit. Toute personne qui conçoit une langue aujourd'hui sans macros ni quelque chose d'équivalent devrait avoir sa licence de conception linguistique enlevée. Voir Converge ( CONVERGEPL.org ) pour savoir comment faire un puissant système de métaprogramming de compilation dans une langue non homoiconique avec Beaucoup de syntaxe.
Je pense que les préprocesseurs sont une béquille pour garder une langue avec une mauvaise marche de puissance expressive. p>
J'ai vu tant d'abus de préprocesseurs que je déteste avec une passion. p>
Le prétraitement de C peut faire des choses vraiment soignées, mais si vous regardez les choses que vous avez utilisées pour vous réalisez que c'est souvent pour simplement ajouter un autre niveau d'abstraction. P>
Donc, ma réponse est la suivante: Vous n'avez pas besoin de préprocesseur si votre langue est suffisamment de haut niveau forte> *. Je n'appellerais pas le prétraitement du mal ou inutile, je dis simplement que plus le langage est abstrait, moins la raison pour laquelle je peux penser pour avoir besoin de prétraitement. P>
* Quel est suffisamment de haut niveau? C'est bien sûr, entièrement subjectif. P>
edit: strong> Bien sûr, je ne fais que référence vraiment à
+1 pour C'est fondamentalement une couche d'abstraction pour l'indépendance de la plate-forme. I>
Les macros ne sont que du mal si vous ne les laissez pas non révéler. Les développeurs C devraient être forcés de ne utiliser que des macros dans des champs spécifiques et non définis lorsqu'ils sont effectués. par exemple, #define Options, #include en-tête, l'en-tête fait un travail et indéfique les options et laisse la structure brute derrière, ou s'il s'agit d'un en-tête utilitaire, vous # y compris, alors vous #define désinstallez et #incluez à nouveau l'en-tête. Et il devrait nettoyer toutes ses macros. Sinon, la portée mondiale devient assez rapide de FUBARD, voir API Windows pour la voir à une extrême.
Un préprocesseur est une phase séparée de la compilation. Bien que le prétraitement puisse être utile dans certains cas, les maux de tête et les bugs qu'il peut causer un problème. P>
en C, le préprocesseur est utilisé principalement pour: p>
Donc, ma réponse est tandis que le préprocesseur nuit à la lisibilité et / ou n'est pas le meilleur moyen de traiter certains problèmes em>. Les plus récentes langues ont tendance à considérer la maintenance du code très important et pour les raisons pour lesquelles le prétraiteur semble être obsolète. P>
Je pense que vous rendant le problème plus grand que cela. Oui, obtenir le droit de transition de phase est un problème difficile. Mais c'est un résolu i> problème difficile: la communauté du régime a compris il y a une décennie il y a des décennies. Vous avez juste besoin de voler leur travail.
Dans le schéma, il ne semble pas y avoir de préprocesseur. Cela signifie que s'il existe, il semble avoir été fait correctement.
Pourquoi la compilation conditionnelle serait-elle le cas d'utilisation le plus légitime pour un préprocesseur? Delphi gère la compilation conditionnelle très bien sans préprocesseur ...
@Marjan Venema: précisément. Donc, même que l'utilisation de l'utilisation a de meilleures alternatives, ce qui ne réduit que même la nécessité de préprocesseurs.
C'est votre langue afin que vous puissiez construire toutes les capacités que vous souhaitez entrer dans la langue elle-même, sans avoir besoin d'un préprocesseur. Je ne pense pas qu'un prétraiteur soit nécessaire, et il ajoute une couche de complexité et d'obscurité au-dessus d'une langue. La plupart des langues modernes n'ont pas de préprocesseurs et, en C ++, vous ne l'utilisez que lorsque vous n'avez pas d'autre choix. p>
Au fait, je crois que D traite la compilation conditionnelle sans préprocesseur. P>
Pour une raison quelconque, d ressemble à une extension de fiction C ++ qui se trouve avoir un compilateur réel
D a statique si code> qui est une instruction code> si code> est évaluée au moment de la compilation au lieu d'exécution.
Cela dépend exactement de quelles autres fonctionnalités que vous proposez. Par exemple, si j'ai un const int n, offrez-vous pour moi de prendre n variables? Avoir n variables membres, prendre un argument pour les construire tous? Créer n fonctions? Effectuer n Opérations qui ne fonctionnent pas nécessairement dans des boucles (par exemple, Pass N arguments)? N Arguments de modèle? Compilation conditionnelle? Constantes qui ne sont pas intégrales? P>
Le préprocesseur C est tellement absurdement puissant dans les mains appropriées, vous auriez besoin de faire une langue sérieusement puissante pour ne pas en garantir une. P>
Un préprocesssor est Cependant, une langue moderne devrait prendre en charge l'équivalent des directives m4 code>. P>
#line code> de C. strong> de telles directives permettent au compilateur de localiser des erreurs dans la source d'origine, même lorsque cette source est intégré dans un générateur d'analyseur ou un générateur LXER ou un programme d'alphabétisation. En d'autres termes, p>
Je dirais que, même si vous éviteriez le pré-processeur pour la plupart de tout ce que vous faites normalement, il est toujours nécessaire. P>
Par exemple, en C ++, afin d'écrire une bibliothèque de test unitaire comme attraper , un pré -Processeur est absolument nécessaire. Ils l'utilisent de deux manières différentes: une pour une expansion d'affirmation 1 sup> et une pour les sections de nidification dans des cas de test 2 p>. P>.
Mais, le pré-processeur ne doit pas être abusé de calculer des calculs de compilation en C ++, où la méta-programmation de const-expressions et de modèles peut être utilisée. P>
Désolé, je n'ai pas assez de réputation pour poster plus de deux liens, alors je le mettais ici ici: P>
Les autres ont souligné, une grande partie de la fonctionnalité fournie par le prétraitement C existe pour compenser les limitations du langage C. Par exemple, Cependant, la seule caractéristique du préprocesseur C qui serait toujours bénéfique dans des langues plus modernes est la directive Premièrement, s'il existe une erreur de syntaxe dans une action, le message d'erreur généré par le Compiler C peut spécifier que l'erreur s'est produite dans, disons, Deuxièmement, les informations de localisation fournies par Les concepteurs de C # et Perl ont judicieusement fourni une directive #include code> et les gardes d'inclusion existent en raison de l'absence d'une instruction code> d'importation de code> et existent largement en raison du manque de fonctions en ligne et de déclarations constantes. P. >
#line code>, car elle supporte l'utilisation de préprocesseurs / compilateurs riches en semi-sémantique. Un exemple, envisagez
YACC code>, qui est une langue spécifique à un domaine (DSL) pour écrire un analyseur comme collection de règles de grammaire BNF. Une caractéristique centrale de
YACC code> est que les morceaux de code C appelé actions em> peuvent être intégrés dans les règles BNF. Lorsqu'une règle BNF est utilisée pour analyser un élément d'entrée, une action intégrée dans cette règle sera exécutée. Le compilateur
YACC code> génère un fichier C qui implémente l'analyseur basé sur BNF spécifié dans le fichier d'entrée et toutes les actions figurant dans le fichier d'entrée YACC sont copiées dans le fichier C généré, mais chaque action est entourée. par
#line code> directives. Cette utilisation de directives
#line code> fournit deux avantages importants. P>
#line code> sont copiées dans des fichiers de code d'objet généré créés par le compilateur C. Donc, si vous utilisez un débogueur pour rechercher un crash de programme, si le bogue qui a provoqué l'origine du crash est originaire d'une action intégrée dans un fichier d'entrée de YACC, le débogueur signalera l'emplacement de cette gamme de buggy de code source comme étant dans
#line code>. Malheureusement, les concepteurs de nombreuses autres langues (Java étant une source à l'esprit) négligé de fournir une directive
#line code>. Pour cette raison, des générateurs d'analyseurs semblables à ceux de YACC pour de nombreuses langues ne sont pas en mesure de communiquer l'emplacement source des actions intégrées aux compilateurs (et donc de débuggers). P>
Je voudrais pas i> dire que le pré-processeur est obsolète en C ++. Beaucoup de choses qu'elle a été utilisée dans C peut être faite à l'aide de modèles, mais il y a encore beaucoup d'utilisations.
C ++ a toujours besoin du préprocesseur sur
#include les fichiers code> à tout le moins - si j'espère que nous pourrons tous convenir qu'il existe des moyens de gérer plusieurs fichiers que d'utiliser un préprocesseur.
@sepp @james oui c'est ce dont je parle. Toute personne qui fait
#define foo (x) ... code> en C ++ ne connaît pas les modèles C ++ ou travaille sur le code hérité.