Wat is een compilerontwerp? Typen, constructiegereedschap, voorbeeld

โšก Slimme samenvatting

De fasen van een compiler beschrijven de zes stappen die broncode omzetten in machinecode: lexicale analyse, syntactische analyse, semantische analyse, generatie van tussenliggende code, codeoptimalisatie en codegeneratie, ondersteund door beheer van de symbolentabel en foutafhandeling.

  • ๐Ÿ”ค Lexicale analyse: De scanner groepeert tekens in tokens en registreert deze in de symbolentabel.
  • ???? Syntaxisanalyse: De parser controleert de grammatica en bouwt een hiรซrarchische parseboom op uit de tokens.
  • โœ”๏ธ Semantische analyse: In deze fase wordt de compatibiliteit van de gegevenstypen en de betekenis ervan geverifieerd aan de hand van de syntaxisboom.
  • โš™๏ธ Code Generatie: Tussenliggende code wordt gegenereerd, geoptimaliseerd en uiteindelijk vertaald naar de doelmachinecode.
  • ๐Ÿ“‹ Ondersteunende routines: Een symbolentabel en een foutafhandelingsroutine werken samen met elke compilatiefase.

Fasen van een compiler met een voorbeeld: het compilatieproces en de stappen

Wat zijn de fasen van het compilerontwerp?

A Compiler Een compiler werkt in verschillende fasen, waarbij elke fase het bronprogramma van de ene representatie naar de andere transformeert. Elke fase ontvangt invoer van de vorige fase en geeft de uitvoer door aan de volgende fase van de compiler. Een compiler heeft 6 fasen. Elk van deze fasen helpt bij het omzetten van de programmeertaal naar machinecode. De fasen van een compiler zijn:

  1. Lexicale analyse
  2. Syntaxisanalyse
  3. semantische analyse
  4. Tussentijdse codegenerator
  5. Code optimizer
  6. Code generator

Fasen van compiler

Fasen van compiler

Al deze fasen zetten de broncode om door deze in tokens te verdelen, parsebomen te creรซren en de broncode in verschillende fasen te optimaliseren.

Fase 1: Lexicale analyse

Lexicale analyse is de eerste fase, waarin de compiler de broncode scant. Dit proces kan van links naar rechts, teken voor teken, plaatsvinden en groepeert deze tekens in tokens.

Hier wordt de tekenstroom van het bronprogramma in betekenisvolle reeksen gegroepeerd door de tokens te identificeren. De corresponderende tokens worden in de symbolentabel ingevoerd en vervolgens doorgegeven aan de volgende fase.

De primaire functies van deze fase zijn:

  • Identificeer de lexicale eenheden in een broncode.
  • Classificeer lexicale eenheden in categorieรซn zoals constanten en gereserveerde woorden, en voer ze in verschillende tabellen in. Commentaar in het bronprogramma wordt genegeerd.
  • Identificeer een token dat geen deel uitmaakt van de taal.

Voorbeeld: x = y + 10

Token Type
X identificatie
= Toewijzingsoperator
Y identificatie
+ Toevoegingsoperator
10 Telefoon Nummer

Fase 2: Syntaxisanalyse

Syntactische analyse draait om het ontdekken van structuur in code. Het bepaalt of een tekst het verwachte formaat volgt. Het belangrijkste doel van deze fase is om te controleren of de door de programmeur geschreven broncode correct is.

Syntactische analyse is gebaseerd op de regels van de specifieke programmeertaal door middel van het construeren van een parseboom met behulp van tokens. Het bepaalt tevens de structuur van de brontaal en de grammatica of syntaxis van de taal.

Hieronder een lijst met taken die in deze fase worden uitgevoerd:

  • Tokens verkrijgen van de lexicale analyzer.
  • Controleer of de uitdrukking syntactisch correct is.
  • Meld alle syntaxfouten.
  • Bouw een hiรซrarchische structuur, ook wel een parseboom genoemd.

Voorbeeld

Elke identificator/elk getal is een expressie. Als x een identificator is en y+10 een expressie, dan is x = y+10 een bewering. Bekijk de parseboom voor het volgende voorbeeld:

(a+b)*c

Voorbeeld van syntaxisanalyse

In de parseboom:

  • Intern knooppunt: record met een operatorveld en twee velden voor onderliggende gegevens.
  • Blad: records met 2 of meer velden; รฉรฉn voor het token en andere informatie over het token.
  • Zorg ervoor dat de onderdelen van het programma op een zinvolle manier op elkaar aansluiten.
  • Verzamelt type-informatie en controleert op typecompatibiliteit.
  • Controleert of de operanden zijn toegestaan โ€‹โ€‹door de brontaal.

Fase 3: Semantische analyse

Semantische analyse controleert de semantische consistentie van de code. Het gebruikt de syntaxisboom van de vorige fase samen met de symbooltabel om te verifiรซren dat de gegeven broncode semantisch consistent is. Ook wordt gecontroleerd of de code een passende betekenis overbrengt.

De semantische analyzer controleert op typefouten, incompatibele operanden, een functieaanroep met onjuiste argumenten, een niet-gedeclareerde variabele, enzovoort.

De functies van de semantische analysefase zijn:

  • Hiermee kunt u verzamelde type-informatie opslaan in de symbolentabel of syntaxisboom.
  • Hiermee kunt u een typecontrole uitvoeren.
  • In geval van een typefout, waarbij er geen exacte typecorrectieregels bestaan โ€‹โ€‹die aan de gewenste bewerking voldoen, wordt een semantische fout weergegeven.
  • Verzamelt type-informatie en controleert op typecompatibiliteit.
  • Controleert of de brontaal de operanden toestaat of niet.

Voorbeeld

float x = 20.2;
float y = x*30;

In de bovenstaande code zal de semantische analyzer het gehele getal 30 omzetten naar het drijvende-komma getal 30.0 voordat de vermenigvuldiging plaatsvindt.

Fase 4: Tussenliggend Code Generatie

Zodra de fase van semantische analyse is voltooid, genereert de compiler tussenliggende code voor de doelmachine. Deze code representeert een programma voor een bepaalde absolute waarde.tract machine.

Tussenliggende code bevindt zich tussen de hogere programmeertaal en de machinecode. Deze tussenliggende code moet zodanig gegenereerd worden dat deze gemakkelijk naar de doelmachinecode kan worden vertaald.

Functies van het tussenliggende Code generatie:

  • Het moet gegenereerd worden op basis van de semantische representatie van het bronprogramma.
  • Bevat de waarden die tijdens het vertaalproces zijn berekend.
  • Hiermee kunt u de tussenliggende code omzetten naar de doeltaal.
  • Hiermee kunt u de prioriteitsvolgorde van de brontaal behouden.
  • Het bevat het juiste aantal operanden van de instructie.

Voorbeeld

Bijvoorbeeld:

total = count + rate * 5

De tussenliggende code met behulp van de adrescodemethode is:

t1 := int_to_float(5)
t2 := rate * t1
t3 := count + t2
total := t3

Fase 5: Code Optimalisatie

De volgende fase is het optimaliseren van de tussenliggende code. In deze fase worden onnodige regels code verwijderd en wordt de volgorde van instructies aangepast om de uitvoering van het programma te versnellen zonder resources te verspillen. Het belangrijkste doel van deze fase is om de tussenliggende code te verbeteren en code te genereren die sneller werkt en minder geheugen in beslag neemt.

De primaire functies van deze fase zijn:

  • Het helpt je om een โ€‹โ€‹afweging te maken tussen uitvoerings- en compilatiesnelheid.
  • Verbetert de uitvoeringsduur van het doelprogramma.
  • Genereert gestroomlijnde code, nog steeds in een tussenliggende representatie.
  • Onbereikbare code verwijderen en ongebruikte variabelen wissen.
  • Instructies die niet worden gewijzigd, worden uit de lus verwijderd.

Voorbeeld: Beschouw de volgende code:

a = intofloat(10)
b = c * a
d = e + b
f = d

Kan worden:

b = c * 10.0
f = e + b

Fase 6: Code Generatie

Code De generatiefase is de laatste fase van een compiler. Deze fase ontvangt invoer van de codeoptimalisatiefase en produceert als resultaat de paginacode of objectcode. Het doel van deze fase is het toewijzen van geheugen en het genereren van verplaatsbare machinecode.

Het wijst ook geheugenlocaties toe aan de variabelen. De instructies in de tussenliggende code worden omgezet in machine-instructies. In deze fase wordt de geoptimaliseerde of tussenliggende code omgezet in de doeltaal.

De doeltaal is machinecode. Daarom worden alle geheugenlocaties en registers tijdens deze fase geselecteerd en toegewezen. De code die in deze fase wordt gegenereerd, wordt uitgevoerd om invoer te verwerken en de verwachte uitvoer te genereren.

Voorbeeld

a = b + 60.0 zou mogelijk in registers vertaald kunnen worden als:

MOVF a, R1
MULF #60.0, R2
ADDF R1, R2

Beheer van symbooltabellen

Een symbolentabel bevat een record voor elke identificator met velden voor de attributen van de identificator. Deze component maakt het voor de compiler gemakkelijker om het identificatorrecord te zoeken en snel op te halen. De symbolentabel helpt ook bij het beheer van de scope. De symbolentabel en de foutafhandeling werken samen met alle fasen, en de symbolentabel wordt dienovereenkomstig bijgewerkt.

Foutafhandelingsroutine

Tijdens het ontwerpproces van een compiler kunnen er in alle onderstaande fasen fouten optreden:

  • Lexicale analyse: Verkeerd gespelde tokens.
  • Syntaxisanalysator: Ontbrekende haakjes.
  • Generator voor tussenliggende code: Niet-overeenkomende operanden voor een operator.
  • Code Optimizer: Wanneer de verklaring niet bereikbaar is.
  • Code Generator: Wanneer het geheugen vol is of er geen geschikte registers zijn toegewezen.
  • Symbolentabellen: Foutmelding: meerdere identificatoren zijn opgegeven.

De meest voorkomende fouten zijn ongeldige tekenreeksen bij het scannen, ongeldige tokenreeksen bij het typen, bereikfouten en parseerfouten bij de semantische analyse.

De fout kan in elk van de bovenstaande fasen optreden. Nadat er fouten zijn gevonden, moet de betreffende fase deze afhandelen om het compilatieproces te kunnen voortzetten. Deze fouten moeten worden gerapporteerd aan de foutafhandelaar, die de fout verwerkt om het compilatieproces te kunnen uitvoeren. Over het algemeen worden de fouten gerapporteerd in de vorm van een bericht.

Veelgestelde vragen

Ja. AI-assistenten kunnen elke fase uitleggen. tracZe laten zien hoe voorbeeldcode wordt omgezet in tokens en parsebomen, en wijzen op syntax- of semantische fouten. Het zijn nuttige hulpmiddelen bij het studeren, maar controleer de uitleg wel aan de hand van het cursusmateriaal.

Machine learning kan voorspellen welke optimalisatiestappen de snelste code opleveren voor een bepaald programma en een bepaalde machine, waardoor keuzes die voorheen handmatig werden gemaakt op basis van heuristieken, worden geoptimaliseerd. De compiler moet er echter nog steeds voor zorgen dat het geoptimaliseerde programma zich exact hetzelfde gedraagt โ€‹โ€‹als het origineel.

De front-end verzorgt de lexicale, syntactische en semantische analyse, plus de tussenliggende code, en is afhankelijk van de brontaal. De back-end verzorgt de optimalisatie en codegeneratie en is afhankelijk van de doelmachine. Deze scheiding vereenvoudigt het aanpassen van de doeltaal.

Nee. Lexicale analyse (scannen) groepeert tekens in tokens, terwijl parsing (syntactische analyse) die tokens rangschikt in een parseboom volgens grammaticaregels. Lexicale analyse wordt eerst uitgevoerd en voert de tokens door aan de parser.

Vat dit bericht samen met: