Delen via


Werken met syntaxis

De syntaxisstructuur is een fundamentele onveranderbare gegevensstructuur die wordt weergegeven door de compiler-API's. Deze bomen vertegenwoordigen de lexicale en syntactische structuur van broncode. Ze dienen twee belangrijke doeleinden:

  • Als u hulpprogramma's, zoals een IDE, invoegtoepassingen, hulpprogramma's voor codeanalyse en herstructureringen wilt toestaan, kunt u de syntactische structuur van broncode in het project van een gebruiker bekijken en verwerken.
  • Hulpprogramma's, zoals herstructureringen en een IDE, inschakelen om broncode op natuurlijke wijze te maken, te wijzigen en opnieuw te rangschikken zonder directe tekstbewerkingen te hoeven gebruiken. Door bomen te maken en te bewerken, kunnen hulpprogramma's eenvoudig broncode maken en opnieuw rangschikken.

Syntaxisstructuren

Syntaxisstructuren zijn de primaire structuur die wordt gebruikt voor compilatie, codeanalyse, binding, herstructureren, IDE-functies en codegeneratie. Er wordt geen deel van de broncode begrepen zonder dat deze eerst wordt geïdentificeerd en gecategoriseerd in een van de vele bekende structurele taalelementen.

Notitie

RoslynQuoter is een opensource-hulpprogramma met de syntaxisfactory-API-aanroepen die worden gebruikt om de syntaxisstructuur van een programma te maken. Als u het live wilt uitproberen, raadpleegt u http://roslynquoter.azurewebsites.net.

Syntaxisstructuren hebben drie belangrijke kenmerken:

  • Ze bevatten alle broninformatie in volledige kwaliteit. Volledige betrouwbaarheid betekent dat de syntaxisstructuur elk stukje informatie bevat dat in de brontekst wordt gevonden, elke grammaticale constructie, elk lexical token en alles daartussen, inclusief witruimte, opmerkingen en preprocessorrichtlijnen. Elke letterlijke letterlijke die in de bron wordt genoemd, wordt bijvoorbeeld exact weergegeven zoals deze is getypt. Syntaxisstructuren leggen ook fouten vast in de broncode wanneer het programma onvolledig of onjuist is gevormd door het weergeven van overgeslagen of ontbrekende tokens.
  • Ze kunnen de exacte tekst produceren waaruit ze zijn geparseerd. Vanuit een syntaxisknooppunt is het mogelijk om de tekstweergave van de substructuur te verkrijgen die is geroot op dat knooppunt. Deze mogelijkheid betekent dat syntaxisstructuren kunnen worden gebruikt als een manier om brontekst te maken en te bewerken. Door een structuur te maken die u hebt gemaakt door implicatie, de equivalente tekst te maken en door een nieuwe boomstructuur te maken op basis van wijzigingen in een bestaande structuur, hebt u de tekst effectief bewerkt.
  • Ze zijn onveranderbaar en thread-veilig. Nadat een boomstructuur is verkregen, is het een momentopname van de huidige status van de code en verandert deze nooit. Hierdoor kunnen meerdere gebruikers tegelijkertijd met dezelfde syntaxisstructuur communiceren in verschillende threads zonder te vergrendelen of dupliceren. Omdat de bomen onveranderbaar zijn en er geen wijzigingen rechtstreeks in een boom kunnen worden aangebracht, helpen fabrieksmethoden om syntaxisstructuren te maken en te wijzigen door extra momentopnamen van de boom te maken. De bomen zijn efficiënt op de manier waarop ze onderliggende knooppunten hergebruiken, zodat een nieuwe versie snel en met weinig extra geheugen opnieuw kan worden opgebouwd.

Een syntaxisstructuur is letterlijk een structuur met structuurgegevens, waarbij niet-terminale structurele elementen bovenliggende andere elementen. Elke syntaxisstructuur bestaat uit knooppunten, tokens en trivia.

Syntaxisknooppunten

Syntaxisknooppunten zijn een van de primaire elementen van syntaxisstructuren. Deze knooppunten vertegenwoordigen syntactische constructies, zoals declaraties, instructies, componenten en expressies. Elke categorie syntaxisknooppunten wordt vertegenwoordigd door een afzonderlijke klasse die is afgeleid van Microsoft.CodeAnalysis.SyntaxNode. De set knooppuntklassen kan niet worden uitgebreid.

Alle syntaxisknooppunten zijn niet-terminale knooppunten in de syntaxisstructuur, wat betekent dat ze altijd andere knooppunten en tokens als onderliggende items hebben. Als onderliggend element van een ander knooppunt heeft elk knooppunt een bovenliggend knooppunt dat toegankelijk is via de SyntaxNode.Parent eigenschap. Omdat knooppunten en bomen onveranderbaar zijn, verandert het bovenliggende element van een knooppunt nooit. De hoofdmap van de structuur heeft een null-bovenliggend item.

Elk knooppunt heeft een SyntaxNode.ChildNodes() methode, die een lijst met onderliggende knooppunten in opeenvolgende volgorde retourneert op basis van hun positie in de brontekst. Deze lijst bevat geen tokens. Elk knooppunt heeft ook methoden om afstammelingen te onderzoeken, zoals DescendantNodes, DescendantTokensof DescendantTrivia - die een lijst vertegenwoordigen van alle knooppunten, tokens of trivia die in de substructuur zijn geroot door dat knooppunt.

Bovendien worden met elke subklasse van het syntaxisknooppunt alle onderliggende elementen weergegeven via sterk getypte eigenschappen. Een knooppuntklasse heeft bijvoorbeeld BinaryExpressionSyntax drie extra eigenschappen die specifiek zijn voor binaire operators: Left, OperatorTokenen Right. Het type Left en Right is ExpressionSyntax, en het type OperatorToken is SyntaxToken.

Sommige syntaxisknooppunten hebben optionele onderliggende items. Een voorbeeld: een IfStatementSyntax heeft een optionele ElseClauseSyntax. Als het onderliggende element niet aanwezig is, retourneert de eigenschap null.

Syntaxistokens

Syntaxistokens zijn de terminals van de taal grammatica, die de kleinste syntactische fragmenten van de code vertegenwoordigen. Ze zijn nooit ouders van andere knooppunten of tokens. Syntaxistokens bestaan uit trefwoorden, id's, letterlijke tekens en leestekens.

Voor efficiëntiedoeleinden is het SyntaxToken type een CLR-waardetype. In tegenstelling tot syntaxisknooppunten is er dus slechts één structuur voor allerlei soorten tokens met een combinatie van eigenschappen die betekenis hebben, afhankelijk van het type token dat wordt weergegeven.

Een letterlijk token voor een geheel getal vertegenwoordigt bijvoorbeeld een numerieke waarde. Naast de onbewerkte brontekst die het token omvat, heeft het letterlijke token een Value eigenschap waarmee u de exacte gedecodeerde gehele waarde kunt zien. Deze eigenschap wordt getypt omdat Object deze mogelijk een van de vele primitieve typen is.

De ValueText eigenschap vertelt u dezelfde informatie als de Value eigenschap. Deze eigenschap wordt echter altijd getypt als String. Een id in C#-brontekst kan Unicode-escapetekens bevatten, maar de syntaxis van de escape-reeks zelf wordt niet beschouwd als onderdeel van de id-naam. Hoewel de onbewerkte tekst van het token wel de escape-reeks bevat, doet de ValueText eigenschap dat niet. In plaats daarvan bevat het de Unicode-tekens die worden geïdentificeerd door de escape. Als de brontekst bijvoorbeeld een id bevat die is geschreven als \u03C0, wordt de ValueText eigenschap voor dit token geretourneerd π.

Trivia syntaxis

Syntaxis trivia vertegenwoordigt de onderdelen van de brontekst die grotendeels onbelangrijk zijn voor een normaal begrip van de code, zoals witruimte, opmerkingen en preprocessorrichtlijnen. Net als syntaxistokens zijn trivia waardetypen. Het ene Microsoft.CodeAnalysis.SyntaxTrivia type wordt gebruikt om allerlei soorten trivia te beschrijven.

Omdat trivia geen deel uitmaken van de syntaxis van de normale taal en overal tussen twee tokens kan worden weergegeven, worden ze niet opgenomen in de syntaxisstructuur als een onderliggend element van een knooppunt. Maar omdat ze belangrijk zijn bij het implementeren van een functie zoals herstructurering en het behoud van volledige betrouwbaarheid met de brontekst, bestaan ze wel als onderdeel van de syntaxisstructuur.

U hebt toegang tot trivia door de token SyntaxToken.LeadingTrivia of SyntaxToken.TrailingTrivia verzamelingen te inspecteren. Wanneer brontekst wordt geparseerd, worden reeksen trivia gekoppeld aan tokens. Over het algemeen is een token eigenaar van alle trivia na het op dezelfde regel tot aan het volgende token. Alle trivia na die regel is gekoppeld aan het volgende token. Het eerste token in het bronbestand haalt alle initiële trivia op en de laatste reeks trivia in het bestand wordt in het token aan het einde van het bestand geplaatst, wat anders geen breedte heeft.

In tegenstelling tot syntaxisknooppunten en tokens hebben syntaxis-trivia geen bovenouders. Maar omdat ze deel uitmaken van de structuur en elk aan één token is gekoppeld, hebt u mogelijk toegang tot het token waaraan het is gekoppeld met behulp van de SyntaxTrivia.Token eigenschap.

Spans

Elk knooppunt, token of trivia kent de positie binnen de brontekst en het aantal tekens dat het uit bestaat. Een tekstpositie wordt weergegeven als een 32-bits geheel getal, een op nul gebaseerde char index. Een TextSpan object is de beginpositie en het aantal tekens, beide weergegeven als gehele getallen. Als TextSpan de lengte nul is, verwijst deze naar een locatie tussen twee tekens.

Elk knooppunt heeft twee TextSpan eigenschappen: Span en FullSpan.

De Span eigenschap is de tekst van het begin van het eerste token in de substructuur van het knooppunt tot het einde van het laatste token. Deze periode omvat geen voorloop- of volg-trivia.

De FullSpan eigenschap is de tekstspanne die de normale spanwijdte van het knooppunt bevat, plus het bereik van een voorloop- of volg-trivia.

Voorbeeld:

      if (x > 3)
      {
||        // this is bad
          |throw new Exception("Not right.");|  // better exception?||
      }

Het instructieknooppunt in het blok heeft een bereik dat wordt aangegeven door de enkele verticale balken (|). Het bevat de tekens throw new Exception("Not right.");. Het volledige bereik wordt aangegeven door de dubbele verticale balken (||). Het bevat dezelfde tekens als de span en de tekens die zijn gekoppeld aan de voorloop- en volg-trivia.

Soorten

Elk knooppunt, token of trivia heeft een SyntaxNode.RawKind eigenschap, van het type System.Int32, waarmee het exacte syntaxiselement wordt aangegeven. Deze waarde kan worden omgezet in een taalspecifieke opsomming. Elke taal, C# of Visual Basic, heeft één SyntaxKind opsomming (Microsoft.CodeAnalysis.CSharp.SyntaxKind en Microsoft.CodeAnalysis.VisualBasic.SyntaxKind, respectievelijk) waarin alle mogelijke knooppunten, tokens en trivia-elementen in de grammatica worden vermeld. Deze conversie kan automatisch worden uitgevoerd door toegang te krijgen tot de CSharpExtensions.Kind of VisualBasicExtensions.Kind extensiemethoden.

Met RawKind de eigenschap kunt u eenvoudig onderscheid maken tussen typen syntaxisknooppunten die dezelfde knooppuntklasse delen. Voor tokens en trivia is deze eigenschap de enige manier om het ene type element van een ander type te onderscheiden.

Eén klas heeft Leftbijvoorbeeld BinaryExpressionSyntax , OperatorTokenen Right als kinderen. De Kind eigenschap maakt onderscheid of het een AddExpression, SubtractExpressionof MultiplyExpression soort syntaxisknooppunt is.

Tip

Het is raadzaam om soorten te controleren met behulp van IsKind extensiemethoden (voor C#) of IsKind (voor VB).

Fouten

Zelfs wanneer de brontekst syntaxisfouten bevat, wordt er een volledige syntaxisstructuur weergegeven die retourneert voor de bron. Wanneer de parser code tegenkomt die niet voldoet aan de gedefinieerde syntaxis van de taal, wordt een van de twee technieken gebruikt om een syntaxisstructuur te maken:

  • Als de parser een bepaald type token verwacht, maar dit niet vindt, kan er een ontbrekend token worden ingevoegd in de syntaxisstructuur op de locatie waar het token werd verwacht. Een ontbrekend token vertegenwoordigt het werkelijke token dat werd verwacht, maar heeft een lege periode en de SyntaxNode.IsMissing eigenschap retourneert true.

  • De parser kan tokens overslaan totdat er een wordt gevonden waar de parsering kan worden voortgezet. In dit geval worden de overgeslagen tokens gekoppeld als een trivia-knooppunt met het type SkippedTokensTrivia.