È possibile (se noioso) scrivere il codice macchina diretto. Forse scrivi il programma nell'assemblatore su un pezzo di carta, e poi lo traduci a mano nelle istruzioni numeriche del codice macchina che inserisci nella memoria della macchina. Puoi anche saltare la fase dell'assemblatore su carta se hai memorizzato i valori numerici di tutte le istruzioni del codice macchina - non insolito in quei giorni, che ci crediate o no!
I primissimi computer sono stati programmati direttamente in binario attivando interruttori fisici. È stato un grande miglioramento della produttività quando l'hardware si è evoluto per consentire al programmatore (o all'assistente per l'immissione dei dati) di inserire il codice in numeri esadecimali tramite una tastiera!
Un assemblatore software è diventato rilevante solo quando è diventata disponibile più memoria (poiché il codice assemblatore occupa più spazio del codice macchina grezzo) e l'hardware si è evoluto per consentire l'input alfanumerico. Quindi i primi assemblatori furono scritti direttamente da persone che parlavano perfettamente il codice macchina.
Quando si dispone di un assemblatore, è possibile scrivere un compilatore per un linguaggio di livello superiore in assemblatore.
La storia di C ha più passaggi. Il primo compilatore C è stato scritto in B (un predecessore di C) che a sua volta è stato scritto in BCPL. BCPL è un linguaggio piuttosto semplice (ad esempio non ha alcun tipo), ma è ancora un passo avanti rispetto al raw assembler. Quindi vedi come gradualmente lingue più complesse vengono costruite in lingue più semplici fino all'assemblatore. E stesso C è un linguaggio piuttosto piccolo e semplice per gli standard odierni.
Oggi, il primo compilatore per una nuova lingua è spesso scritto in C, ma quando la lingua raggiunge una certa maturità viene spesso riscritta "in sé". Il primo compilatore Java è stato scritto in C, ma in seguito riscritto in Java. Il primo compilatore C # è stato scritto in C ++, ma recentemente è stato riscritto in C #. Il compilatore / interprete Python è scritto in C, ma il progetto PyPy è un tentativo di riscriverlo in Python.
Tuttavia, non è sempre possibile scrivere un compilatore / interprete per una lingua nella lingua stessa. Esiste un interprete JavaScript scritto in JavaScript, ma i compilatori / interpreti nei browser attuali sono ancora scritti in C o C ++ per motivi di prestazioni. JavaScript scritto in JavaScript è semplicemente troppo lento.
Ma non devi usare C come "lingua iniziale" per un compilatore. Il primo compilatore F # è stato scritto in OCaml, che è l'altra lingua che è più strettamente correlata a F #. Quando il compilatore è stato completato, è stato riscritto in F #. Il primo compilatore per Perl 6 è stato scritto in Haskell (un linguaggio funzionale puro molto diverso dal Perl) ma ora ha un compilatore scritto in C.
Un caso interessante è Rust, in cui il primo compilatore è stato scritto in OCaml (ora è stato riscritto in Rust). Ciò è notevole perché OCaml è generalmente considerato di livello superiore rispetto a Rust, che è un linguaggio di sistemi più vicino al metallo. Quindi non sono sempre linguaggi di livello superiore implementati in linguaggi di livello inferiore, ma potrebbe anche essere il contrario.