C'è qualche vera differenza tra un compilatore e un assemblatore?


14

C'è qualche differenza tra i due? Secondo il libro di Ullman , i compilatori convertono una lingua in un'altra lingua (di solito di basso livello), così come un assemblatore. In che modo i due sono diversi?


1
Un assemblatore è un compilatore che esegue una serie specifica di attività. I termini sono in qualche modo divergenti nella pratica, ma si applica la definizione base di "compilatore" (traduzione tra le lingue).
Raffaello

Tutti gli assemblatori sono compilatori (semplici), poiché trasformano una lingua in un'altra. Non tutti i compilatori sono assemblatori.
user253751

Risposte:


16

Un assemblatore traduce il codice assembly in codice macchina. La traduzione è meccanica e può essere eseguita in un solo modo. Al contrario, un compilatore ha più libertà quando compila il linguaggio di programmazione pertinente: può ottimizzare, ad esempio, e anche compilatori non ottimizzati producono codice diverso. Inoltre, i compilatori possono essere scritti in un modo che separa "front-end" (corrispondente al linguaggio di programmazione) e "back-end" (corrispondente all'architettura del computer), mentre con gli assemblatori i due sono sempre gli stessi.


2
Perché la traduzione può essere eseguita in un solo modo? Ciò significa che il codice asm di origine non può essere generato per un determinato codice macchina (e architettura di destinazione)? Mi sembra poco intuitivo. Perché se una determinata istruzione del codice macchina può essere associata a più istruzioni asm, come fa la macchina a decidere quale istruzione eseguire? Mi sto perdendo qualcosa?
Utku,

2
UNT(UN)UN

Grazie, vedo anche che nel libro di Ullman, un compilatore ha un front-end e un back-end. Se ho ragione, il backend esegue l'ottimizzazione in una lingua intermedia, la generazione del codice macchina e l'ottimizzazione del codice macchina, e ciascuna delle tre attività può essere eseguita in più di un modo. la parte "backend" è un assemblatore? La lingua intermedia è una lingua assembly? Credo di si, ma la tua risposta menziona che un assemblatore fa il suo lavoro in un solo modo.
Tim


La lingua intermedia di solito si riferisce a una lingua indipendente dalla macchina.
Yuval Filmus,

11

La linea di fondo è che è più divertente scrivere un compilatore che un assemblatore. I linguaggi di assemblaggio sono generalmente progettati per essere quasi banali da analizzare e controllare i tipi e tendono a coinvolgere molti generatori basati su tabella ("il codice operativo per aggiungere è 01110", "per le istruzioni di caricamento il registro dell'operando di destinazione è specificato dai bit da 17 a 21 "). Di solito la parte più interessante di un assemblatore è la parte che risolve le etichette simboliche in numeri.

Tuttavia , la maggior parte degli assemblatori può eseguire una piccola quantità di aritmetica (aggiungendo insieme etichette simboliche con piccole costanti, per esempio) e la maggior parte degli assemblatori ha o è integrato con una funzione di elaborazione delle macro. (Sulla maggior parte dei sistemi Unix la funzione macro è effettivamente fornita eseguendo il pre-processore C sull'assemblaggio prima di passarlo al proprio assemblatore.)

L'assemblatore MIPS ha dovuto fare un passo oltre e ha preso alcune interessanti decisioni sulla generazione del codice e ha fatto una piccola quantità di ottimizzazione. Il linguaggio della macchina MIPS richiede sequenze di codice diverse per caricare diverse costanti, ad esempio, e quindi l'assemblatore doveva scegliere la sequenza di codici dopo aver costruito la costante . Inoltre, il codice macchina MIPS aveva il concetto di slot di ritardo , ma era responsabilità dell'assemblatore estrarre questi elementi e presentare al compilatore un linguaggio di assemblaggio astratto più "normale". Quindi l'assemblatore MIPS deve eseguire una pianificazione delle istruzioni locali.

La distinzione è ulteriormente offuscata da alcune delle opere di Norman Ramsey , in particolare il suo linguaggio di assemblaggio portatile C. (L'articolo pertinente è Ramsey e Peyton Jones, "Un singolo linguaggio intermedio che supporta molteplici implementazioni di eccezioni", Prog. Lang. Impl. E Dsgn. , (PLDI-21): 285–298, 2000 ). E infine, lì è anche un Typed Assembly Language di David Walker e Greg Morrisett con un assemblatore in grado di garantire la sicurezza della memoria.


0

Un po 'di risposta semplificata qui, la realtà è più complicata. Mi aspetto che la differenza tra un assemblatore (A) e un compilatore (C) sia tra le altre cose:

  1. Una riga di codice sorgente si riferisce direttamente a un codice operativo CPU (A) oppure no (C)
  2. Molto dipendente dalla CPU effettiva (A) o indipendente dalla macchina (C)

Tendiamo a chiamare il linguaggio assembly "basso livello" e la lingua di origine che un compilatore comprende "alto livello" (questa è una semplificazione grossolana, ma comunque).

Nel linguaggio assembly è possibile ad esempio eseguire un'operazione aggiuntiva dicendo:

  • aggiungere a, b (per una CPU specifica)
  • aggiungi R5, R6 (per una CPU diversa)
  • aggiungi (A5), D2 (per una CPU diversa)

In una lingua di alto livello potresti scrivere:

  • x = y + z;

E questo potrebbe comportare un'istruzione o centinaia di istruzioni a seconda di una serie di circostanze, una è la CPU per la quale il compilatore crea istruzioni.

Come puoi vedere, il linguaggio di origine dell'assemblaggio è il più delle volte: (A) una riga di codice sorgente fornisce una riga di codici operativi della CPU e dipende molto dalla CPU di destinazione. Un compilatore di linguaggio di alto livello (C) gestisce tutti questi dettagli per te: una riga di codice sorgente potrebbe diventare zero, uno o più codici operativi della CPU e il compilatore gestisce i dettagli di ciò che la CPU può fare.

Oggi un compilatore consiste spesso in diverse fasi. Potrebbero essere chiamati frontend / backend o essere chiamati altre cose. In genere li vedo come quattro fasi:

  1. La prima fase legge il codice sorgente effettivo e crea una rappresentazione interna. Questa fase conosce l'attuale lingua di origine.
  2. La seconda fase esamina la rappresentazione interna ed esegue una serie di ottimizzazioni. Al giorno d'oggi, il compilatore cercherebbe in genere di rendere il programma più veloce e di non preoccuparsi se diventa più grande. L'ottimizzazione viene eseguita sulla rappresentazione interna. È interessante notare che parti di questo potrebbero essere generiche per diverse lingue.
  3. Il terzo stadio prende la rappresentazione interna e crea il codice effettivo per la CPU selezionata. Potrebbero esserci diverse versioni di questo stage, destinate a CPU diverse. In effetti è possibile scrivere una volta il codice sorgente e quindi compilarlo per diversi CPUS.
  4. Preparativi finali per "impacchettare" il programma (questa fase potrebbe essere un collegamento).

Scrivere buoni compilatori è una professione altamente qualificata: creare un compilatore in linguaggio giocattolo può essere svolto in un pomeriggio da un amatuer (o bene, leggermente più a lungo).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.