Existe-t-il une réelle différence entre un compilateur et un assembleur?

15

Y a-t-il une différence entre les deux? Selon le livre d'Ullman , les compilateurs convertissent une langue en une autre langue (généralement de bas niveau), tout comme un assembleur. En quoi les deux sont-ils différents?

gpuguy
la source
1
Un assembleur est un compilateur qui effectue un ensemble spécifique de tâches. Les termes ont quelque peu divergé dans la pratique, mais la définition de base de "compilateur" (traduire entre les langues) s'applique.
Raphael
Tous les assembleurs sont des compilateurs (simples), car ils transforment un langage en un autre. Tous les compilateurs ne sont pas des assembleurs.
user253751

Réponses:

16

Un assembleur traduit le code assembleur en code machine. La traduction est mécanique et ne peut se faire que d'une seule façon. En revanche, un compilateur a plus de liberté lorsqu'il compile le langage de programmation pertinent - il peut optimiser, par exemple, et même des compilateurs non optimisants produisent du code différent. De plus, les compilateurs peuvent être écrits d'une manière qui sépare le "front-end" (correspondant au langage de programmation) et le "back-end" (correspondant à l'architecture informatique), alors qu'avec les assembleurs, les deux sont toujours les mêmes.

Yuval Filmus
la source
2
Pourquoi la traduction ne peut-elle être effectuée que d'une seule manière? Est-ce à dire que le code asm d'origine ne peut pas être généré pour un code machine (et une architecture cible) donnés? Cela me semble contre-intuitif. Parce que si une instruction de code machine donnée peut correspondre à plusieurs instructions asm, comment la machine décide-t-elle quelle instruction exécuter? Suis-je en train de manquer quelque chose?
Utku
3
UNET(UNE)UNE
Merci, je vois aussi que dans le livre d'Ullman, un compilateur a un frontal et un backend. Si je ne me trompe pas, le backend effectue l'optimisation dans un langage intermédiaire, la génération de code machine et l'optimisation du code machine, et chacune des trois tâches peut être effectuée de plusieurs manières. la partie "backend" est-elle un assembleur? Le langage intermédiaire est-il un langage d'assemblage? Je suppose que oui, mais votre réponse mentionne qu'un assembleur ne fait son travail que d'une seule façon.
Tim
Un langage intermédiaire fait généralement référence à un langage indépendant de la machine.
Yuval Filmus
11

L'essentiel est qu'il est plus amusant d'écrire un compilateur qu'un assembleur. Les langages d'assemblage sont généralement conçus pour être presque triviaux pour l'analyse et la vérification de type et ont tendance à impliquer de nombreux générateurs pilotés par table ("l'opcode for add is 01110", "pour les instructions de chargement, le registre d'opérande de destination est spécifié par les bits 17 à 21). "). Habituellement, la partie la plus intéressante d'un assembleur est la partie qui résout les étiquettes symboliques en nombres.

Cependant , la plupart des assembleurs peuvent faire une petite quantité d'arithmétique (en additionnant des étiquettes symboliques avec de petites constantes, par exemple) et la plupart des assembleurs ont ou sont intégrés à une fonction de macro-traitement. (Sur la plupart des systèmes Unix, la fonction macro est en fait fournie en exécutant le pré-processeur C sur l'assembly avant de le passer à l'assembleur proprement dit.)

L'assembleur MIPS a dû aller plus loin et a pris des décisions intéressantes de génération de code et a fait une petite quantité d'optimisation. Le langage machine MIPS nécessite différentes séquences de code pour charger différentes constantes, par exemple, et l'assembleur a donc dû choisir la séquence de code après avoir construit la constante . En outre, le code machine MIPS avait la notion de créneaux de retard , mais il était de la responsabilité de l'assembleur de les résumer et de présenter un langage d'assemblage abstrait plus "normal" au compilateur. Par conséquent, l'assembleur MIPS doit effectuer une planification des instructions locales.

La distinction est encore brouillée par certains travaux de Norman Ramsey , en particulier son langage d'assemblage portable C-- . (L'article pertinent est Ramsey et Peyton Jones, «Un seul langage intermédiaire qui prend en charge plusieurs implémentations d'exceptions», Prog. Lang. Impl. Et Dsgn. , (PLDI-21): 285-298, 2000. ) Et enfin, il y a est également un langage d'assemblage typé de David Walker et Greg Morrisett avec un assembleur qui peut garantir la sécurité de la mémoire.

Logique errante
la source
0

Un peu de réponse simplifiée ici, la réalité est plus compliquée. Je m'attendrais à ce que la différence entre un assembleur (A) et un compilateur (C) soit entre autres:

  1. Une ligne de code source se rapporte directement à un opcode CPU (A) ou non (C)
  2. Dépend fortement du CPU (A) ou de la machine (C)

Nous avons tendance à appeler le langage d'assemblage "bas niveau" et le langage source qu'un compilateur comprend "haut niveau" (c'est une simplification grossière, mais quand même).

En langage assembleur, vous pouvez par exemple faire une opération d'ajout en disant:

  • ajouter a, b (pour un processeur spécifique)
  • ajouter R5, R6 (pour un autre processeur)
  • ajouter (A5), D2 (pour un autre processeur)

Dans une langue de haut niveau, vous pourriez écrire:

  • x = y + z;

Et cela pourrait entraîner une instruction ou des centaines d'instructions en fonction d'un certain nombre de circonstances, dont le processeur pour lequel le compilateur crée des instructions.

Comme vous pouvez le voir, le langage source de l'assembly est le plus souvent: (A) une ligne de code source donne une ligne d'opcodes CPU et cela dépend beaucoup du CPU que vous ciblez. Un compilateur de langage (C) de haut niveau gère tous ces détails pour vous - une ligne de code source peut devenir zéro, un ou plusieurs opcodes CPU et le compilateur gère les détails de ce que le CPU peut faire.

Aujourd'hui, un compilateur se compose souvent de plusieurs étapes différentes. Ils peuvent être appelés frontend / backend ou être appelés d'autres choses. Je les vois généralement comme quatre étapes:

  1. La première étape lit le code source réel et crée une représentation interne. Cette étape connaît la langue source réelle.
  2. La deuxième étape examine la représentation interne et effectue un certain nombre d'optimisations. De nos jours, le compilateur cherche généralement à rendre le programme plus rapide et à ne pas s'en soucier s'il grossit. L'optimisation se fait sur la représentation interne. Fait intéressant, certaines parties pourraient être génériques pour plusieurs langues différentes.
  3. La troisième étape prend la représentation interne et crée le code réel pour le CPU sélectionné. Il peut y avoir plusieurs versions différentes de cette étape, ciblant différents CPU. En effet, vous pouvez écrire une fois le code source, puis le compiler pour différents CPUS.
  4. Préparatifs finaux pour "emballer" le programme (cette étape pourrait être un lien).

Écrire de bons compilateurs est une profession hautement qualifiée - faire un compilateur de langage jouet peut être fait en un après-midi par un amateur (ou bien, un peu plus long).

ghellquist
la source