Kennisbank

Compiler: de vertaler die mensentaal omzet in machinetaal

Bijgewerkt: 8 september 2026 · 7 min leestijd

Elke keer dat je een app opent, een website bezoekt of een spelletje speelt op je telefoon, is daar ergens een compiler aan te pas gekomen. Een compiler is een programma dat broncode - de tekst die een programmeur schrijft in een taal zoals C++, Java of Rust - omzet in machinecode: de reeksen enen en nullen die een processor daadwerkelijk kan uitvoeren. Zonder dit tussenstapje zou geen enkele computer iets kunnen doen met de code die mensen schrijven, hoe slim die code ook in elkaar zit.

Een handige vergelijking is die met een juridisch vertaler. Een advocaat schrijft een contract in begrijpelijk Nederlands, maar voor gebruik in een ander land moet dat contract vertaald worden naar een taal die daar rechtsgeldig is - met exact de juiste juridische termen en zinsconstructies. De inhoud en bedoeling blijven hetzelfde, maar de vorm verandert volledig. Een compiler doet iets vergelijkbaars: de bedoeling van de programmeur blijft overeind, maar de tekst verandert van leesbare instructies naar strikte, machineleesbare commando's. En net als een goede vertaler controleert een compiler onderweg ook op fouten en inconsistenties.

Wat is het precies?

Het compilatieproces verloopt in een aantal vaste stappen, die meestal na elkaar worden doorlopen. De eerste stap heet lexicale analyse. Hierbij knipt de compiler de broncode op in kleine, betekenisvolle brokjes, tokens genoemd: woorden zoals if, while, variabelenamen, getallen en leestekens. Dit is te vergelijken met het herkennen van losse woorden in een zin voordat je de zin als geheel begrijpt.

Daarna volgt parsing, ook wel syntaxisanalyse genoemd. De compiler controleert of de volgorde van tokens grammaticaal klopt volgens de regels van de programmeertaal, en bouwt een boomstructuur op - de zogeheten syntaxisboom - die de opbouw van het programma weergeeft. Vergelijk het met een zinsontleding op de middelbare school: onderwerp, persoonsvorm, lijdend voorwerp, allemaal in een logische boomstructuur.

Vervolgens komt de semantische analyse. Hier checkt de compiler of de code ook inhoudelijk klopt: worden variabelen gebruikt voordat ze bestaan, klopt het datatype (probeer je bijvoorbeeld geen tekst bij een getal op te tellen), en wordt elke functie aangeroepen met het juiste aantal argumenten? Dit heet ook wel typecontrole. Fouten die hier worden gevonden, zijn de rode kronkellijntjes die programmeurs in hun editor zien voordat ze de code zelfs maar hebben uitgevoerd.

Als de code correct is bevonden, volgt optimalisatie. De compiler herschrijft de interne representatie van het programma zodat het uiteindelijke resultaat sneller draait of minder geheugen gebruikt, zonder dat de betekenis verandert. Denk aan het weglaten van berekeningen waarvan de uitkomst nooit gebruikt wordt, of het combineren van stappen die apart minder efficiënt zouden zijn.

De laatste stap is codegeneratie: het omzetten van de geoptimaliseerde, taalonafhankelijke representatie naar de specifieke machinecode van het doelplatform, bijvoorbeeld voor een Intel-processor in een laptop of een ARM-chip in een telefoon.

Hierbij is een belangrijk onderscheid te maken tussen vooraf compileren (Ahead-Of-Time, afgekort AOT) en interpreteren of just-in-time compileren (JIT). Bij AOT-compilatie wordt het hele programma in één keer vertaald voordat het wordt uitgevoerd, zoals bij C of Rust. Bij interpretatie wordt de code regel voor regel gelezen en direct uitgevoerd, zonder dat er eerst machinecode wordt gegenereerd - dat is trager, maar flexibeler. JIT-compilatie is een tussenvorm: de code wordt tijdens het draaien vertaald, waarbij vaak gebruikte stukken alsnog worden omgezet in snelle machinecode. Deze aanpak wordt gebruikt door bijvoorbeeld JavaScript-engines in webbrowsers.

Wat wil men ermee bereiken?

Het belangrijkste doel van een compiler is abstractie: programmeurs kunnen werken in een taal die voor mensen te begrijpen is, met woorden en structuren die aansluiten bij hoe wij denken, in plaats van rechtstreeks in enen en nullen te moeten programmeren. Dat maakt software ontwikkelen sneller, minder foutgevoelig en toegankelijker voor veel meer mensen.

Een tweede doel is performance. Door tijdens de optimalisatiefase slim naar de code te kijken, kan een compiler vaak een programma laten draaien dat merkbaar sneller is dan wat een programmeur letterlijk had opgeschreven, zonder dat die programmeur zelf ingewikkelde trucs hoeft toe te passen.

Ten derde speelt portabiliteit een grote rol: dezelfde broncode kan door verschillende compilers worden vertaald naar machinecode voor uiteenlopende processors en besturingssystemen. Eén programma, geschreven in bijvoorbeeld C, kan zo zowel op een Windows-pc als op een Linux-server draaien, mits er voor elk platform een geschikte compiler is.

Tot slot draagt een compiler bij aan vroege foutdetectie. Veel fouten - verkeerde datatypes, ontbrekende variabelen, syntaxisfouten - worden al tijdens het compileren opgespoord, in plaats van pas wanneer het programma bij een eindgebruiker crasht. Dat scheelt tijd, geld en soms zelfs veiligheidsrisico's.

Voorbeelden uit de praktijk

GCC (GNU Compiler Collection) is een van de oudste nog actief gebruikte compilerprojecten. Richard Stallman begon eraan in 1987 als onderdeel van het GNU-project, en GCC ondersteunt inmiddels talen als C, C++ en Fortran. Grote delen van het Linux-ecosysteem worden ermee gebouwd.

LLVM is een compilerinfrastructuur die rond 2000 werd gestart door Chris Lattner, destijds student aan de University of Illinois. LLVM is uitgegroeid tot de basis voor een reeks moderne compilers, waaronder Clang (voor C/C++), en de compilers van Rust en Swift. LLVM levert herbruikbare bouwstenen, zodat niet elke nieuwe taal het optimalisatie- en codegeneratiewerk opnieuw hoeft uit te vinden.

V8 is de JavaScript-engine die Google in 2008 introduceerde voor de Chrome-browser en die sindsdien ook de basis vormt van Node.js. V8 gebruikt JIT-compilatie om JavaScript-code tijdens het draaien te vertalen naar snelle machinecode, wat webpagina's en JavaScript-toepassingen aanzienlijk sneller maakt dan pure interpretatie.

De Rust-compiler (rustc) voert tijdens het compileren strenge controles uit op geheugenveiligheid, zoals het voorkomen van toegang tot geheugen dat al is vrijgegeven. Dat maakt hele categorieën beveiligingsfouten die in talen als C en C++ vaak voorkomen, in Rust-programma's veel zeldzamer - al blijft menselijke fouten elders altijd mogelijk.

De TypeScript-compiler (tsc), door Microsoft geïntroduceerd in 2012, vertaalt geen machinecode maar een andere leesbare taal: TypeScript-code met typecontrole wordt omgezet naar gewone JavaScript, die door browsers wordt begrepen. Dit heet transpilatie, een variant van compilatie waarbij bron- en doeltaal beide voor mensen leesbaar zijn.

Hoe ver is de techniek?

Compilertechnologie bestaat al sinds de jaren vijftig van de vorige eeuw en is in de kern volwassen: de basisprincipes van lexicale analyse, parsing en codegeneratie liggen grotendeels vast en worden op universiteiten al decennialang op vergelijkbare wijze onderwezen. Toch is het veld allesbehalve stilgevallen.

Een van de recentere ontwikkelingen is WebAssembly, een compilatiedoel dat sinds ongeveer 2017 breed door browsers wordt ondersteund. Hiermee kunnen talen als C++ of Rust worden gecompileerd naar code die in de browser bijna even snel draait als native software, wat nieuwe toepassingen mogelijk maakt zoals zware rekentaken in webapplicaties.

Ook wordt er geëxperimenteerd met machine learning binnen compilers zelf. Google publiceerde rond 2022 onderzoek naar MLGO, een aanpak waarbij een getraind model beslissingen neemt over optimalisaties die traditioneel met vaste regels (heuristieken) werden gemaakt. De resultaten zijn wisselend en het is nog geen gangbare industriestandaard, maar het laat zien dat er ruimte is voor verbetering binnen een op het oog uitontwikkeld vakgebied.

Een derde ontwikkeling betreft veiligheid. Sinds de ontdekking van de processorkwetsbaarheden Spectre en Meltdown in 2018 passen compilerbouwers speciale beschermende maatregelen toe die bepaalde soorten aanvallen via zogeheten speculatieve uitvoering van processors bemoeilijken. Dit is een voorbeeld van hoe compilers niet alleen software vertalen, maar ook meedenken over hardwarebeveiliging.

Verder ontwikkelt het LLVM-project sinds enkele jaren MLIR (Multi-Level Intermediate Representation), een raamwerk dat het makkelijker moet maken om compilers te bouwen voor gespecialiseerde chips, zoals AI-versnellers die machine-learning-berekeningen uitvoeren. Dit speelt in op de groeiende diversiteit aan hardware, van gewone processors tot chips die specifiek voor kunstmatige intelligentie zijn ontworpen.

De belangrijkste obstakels blijven de toenemende complexiteit van moderne processors, waardoor optimalisatie steeds ingewikkelder wordt, en de afweging tussen compilatietijd en optimalisatiekwaliteit: grondiger optimaliseren kost vaak meer rekentijd tijdens het compileren zelf.

Wie werken eraan?

Compilerontwikkeling is grotendeels een samenspel van grote techbedrijven, non-profitorganisaties en universiteiten. De LLVM Foundation begeleidt de ontwikkeling van het LLVM-project, met bijdragen van onder meer Apple, Google en talloze individuele ontwikkelaars.

Google speelt een grote rol via de V8-engine, het MLIR-project en de compiler voor de programmeertaal Go. De Rust Foundation, opgericht in 2021 met steun van onder meer AWS, Google, Huawei, Microsoft en Mozilla, ondersteunt de verdere ontwikkeling van de Rust-compiler. Microsoft onderhoudt naast de TypeScript-compiler ook Roslyn, de compilerinfrastructuur voor C# en .NET.

Daarnaast dragen academische instituten zoals MIT, Stanford en de ETH Zürich substantieel bij aan compileronderzoek, met name op het gebied van optimalisatietechnieken en programmeertaalontwerp. Veel van dit werk vindt plaats in open source gemeenschappen, waarbij vrijwilligers wereldwijd meewerken aan projecten als GCC en LLVM naast betaalde ontwikkelaars van de grote bedrijven.

Verder lezen