Präverarbeitungsrichtlinien

Sobald eine Datei lexikalisch analysiert wurde, treten mehrere Arten von Quellvorverarbeitung auf. Die wichtigste, bedingte Kompilierung bestimmt, welche Quelle von der syntaktischen Grammatik verarbeitet wird; Zwei andere Arten von Direktiven – externe Quelldirektiven und Regionsdirektiven – stellen Metainformationen zur Quelle bereit, wirken sich jedoch nicht auf die Kompilierung aus.

Bedingte Kompilierung

Die bedingte Kompilierung steuert, ob Sequenzen logischer Zeilen in tatsächlichen Code übersetzt werden. Zu Beginn der bedingten Kompilierung werden alle logischen Zeilen aktiviert; Das Einschließen von Zeilen in bedingte Kompilierungsanweisungen kann diese Zeilen in der Datei jedoch selektiv deaktivieren, sodass sie während des restlichen Kompilierungsprozesses ignoriert werden.

CCStart
    : CCStatement*
    ;

CCStatement
    : CCConstantDeclaration
    | CCIfGroup
    | LogicalLine
    ;

CCExpression
    : LiteralExpression
    | CCParenthesizedExpression
    | CCSimpleNameExpression
    | CCCastExpression
    | CCOperatorExpression
    | CCConditionalExpression
    ;

CCParenthesizedExpression
    : '(' CCExpression ')'
    ;

CCSimpleNameExpression
    : Identifier
    ;

CCCastExpression
    : 'DirectCast' '(' CCExpression ',' TypeName ')'
    | 'TryCast' '(' CCExpression ',' TypeName ')'
    | 'CType' '(' CCExpression ',' TypeName ')'
    | CastTarget '(' CCExpression ')'
    ;

CCOperatorExpression
    : CCUnaryOperator CCExpression
    | CCExpression CCBinaryOperator CCExpression
    ;

CCUnaryOperator
    : '+' | '-' | 'Not'
    ;

CCBinaryOperator
    : '+'     | '-'     | '*'   | '/'       | '\\'     | 'Mod' | '^' | '='
    | '<' '>' | '<'     | '>'   | '<' '='   | '>' '='  | '&'
    | 'And'   | 'Or'    | 'Xor' | 'AndAlso' | 'OrElse'
    | '<' '<' | '>' '>'
    ;

CCConditionalExpression
    : 'If' '(' CCExpression ',' CCExpression ',' CCExpression ')'
    | 'If' '(' CCExpression ',' CCExpression ')'
    ;

Beispiel: das Programm

#Const A = True
#Const B = False

Class C

#If A Then
    Sub F()
    End Sub
#Else
    Sub G()
    End Sub
#End If

#If B Then
    Sub H()
    End Sub
#Else
    Sub I()
    End Sub
#End If

End Class

erzeugt genau die gleiche Abfolge von Token wie das Programm.

Class C
    Sub F()
    End Sub

    Sub I()
    End Sub
End Class

Die in bedingten Kompilierungsdirektiven zulässigen Konstantenausdrücke sind eine Teilmenge allgemeiner Konstantenausdrücke.

Der Präprozessor ermöglicht Leerzeichen und explizite Zeilenfortsetzungen vor und nach jedem Token.

Bedingte Konstantendirektiven

Bedingte Konstantenanweisungen definieren Konstanten, die in einem separaten Deklarationsbereich für die bedingte Kompilierung vorhanden sind, der auf die Quelldatei festgelegt ist.

CCConstantDeclaration
    : '#' 'Const' Identifier '=' CCExpression LineTerminator
    ;

Der Deklarationsraum ist besonders darauf ausgerichtet, dass keine explizite Deklaration bedingter Kompilierungskonstanten erforderlich ist – bedingte Konstanten können implizit in einer Direktive zur bedingten Kompilierung definiert werden.

Vor dem Zuweisen eines Werts weist eine konstante bedingte Kompilierung den Wert Nothingauf. Wenn eine bedingte Kompilierungskonstante einem Wert zugewiesen wird, der ein konstanter Ausdruck sein muss, wird der Typ der Konstante zum Typ des ihm zugewiesenen Werts. Eine bedingte Kompilierungskonstante kann mehrmals in einer Quelldatei neu definiert werden.

Der folgende Code druckt z. B. nur die Zeichenfolge about to print value und den Wert von Test.

Module M1
    Sub PrintValue(Test As Integer)

#Const DebugCode = True

#If DebugCode Then
        Console.WriteLine("about to print value")
#End If

#Const DebugCode = False

        Console.WriteLine(Test)

#If DebugCode Then
        Console.WriteLine("printed value")
#End If

    End Sub
End Module

Die Kompilierungsumgebung kann auch bedingte Konstanten in einem Deklarationsbereich für die bedingte Kompilierung definieren.

Anweisungen für die bedingte Kompilierung

Bedingte Kompilierungsdirektiven steuern die bedingte Kompilierung.

CCIfGroup
    : '#' 'If' CCExpression 'Then'? LineTerminator CCStatement*
    CCElseIfGroup* CCElseGroup? '#' 'End' 'If' LineTerminator
    ;

CCElseIfGroup
    : '#' ElseIf CCExpression 'Then'? LineTerminator CCStatement*
    ;

CCElseGroup
    : '#' 'Else' LineTerminator CCStatement*
    ;

Bedingte Konstanten können nur auf Konstantenausdrücke und bedingte Kompilierungskonstanten verweisen. Jeder der Konstantenausdrücke innerhalb einer einzelnen Gruppe für die bedingte Kompilierung wird ausgewertet und in den Boolean Typ in textualer Reihenfolge konvertiert, bis einer der bedingten Ausdrücke ausgewertet wird True. Wenn ein Ausdruck nicht konvertierbar Booleanist, ergibt sich ein Kompilierungszeitfehler. Zulässige Semantik und Binäre Zeichenfolgenvergleiche werden immer verwendet, wenn bedingte Kompilierungskonstantenausdrücke ausgewertet werden, unabhängig von Option Direktiven oder Kompilierungsumgebungseinstellungen.

Alle Zeilen, die von der Gruppe eingeschlossen sind, einschließlich geschachtelter Direktiven für die bedingte Kompilierung, sind deaktiviert, mit Ausnahme von Zeilen zwischen der Anweisung, die den True Ausdruck und die nächste bedingte Anweisung der Gruppe enthält, oder Zeilen zwischen der Else Anweisung und der End If Anweisung, wenn eine Else in der Gruppe angezeigt wird und alle Ausdrücke ausgewertet werden False.

In diesem Beispiel wird der Aufruf WriteToLog in der Direktive für die Trace bedingte Kompilierung nicht verarbeitet, da die umgebende Debug bedingte Kompilierungsdirektive ausgewertet Falsewird.

#Const Debug = False   ' Debugging off
#Const Trace = True    ' Tracing on

Class PurchaseTransaction
    Sub Commit()

#If Debug Then
        CheckConsistency()
#If Trace Then
        WriteToLog(Me.ToString())
#End If
#End If
        ...
    End Sub
End Class

Richtlinien für externe Quellen

Eine Quelldatei kann externe Quelldirektiven enthalten, die eine Zuordnung zwischen Quellzeilen und Text außerhalb der Quelle angeben.

ESDStart
    : ExternalSourceStatement*
    ;

ExternalSourceStatement
    : ExternalSourceGroup
    | LogicalLine
    ;

ExternalSourceGroup
    : '#' 'ExternalSource' '(' StringLiteral ',' IntLiteral ')' LineTerminator
      LogicalLine* '#' 'End' 'ExternalSource' LineTerminator
    ;

Externe Quelldirektiven wirken sich nicht auf die Kompilierung aus und sind möglicherweise nicht geschachtelt. Beispiel:

Module Test
    Sub Main()

#ExternalSource("c:\wwwroot\inetpub\test.aspx", 30)
        Console.WriteLine("In test.aspx")
#End ExternalSource

    End Sub
End Module

Regionsdirektiven

Regionsdirektiven gruppieren Zeilen des Quellcodes, wirken sich jedoch nicht auf die Kompilierung aus. Die gesamte Gruppe kann in der integrierten Entwicklungsumgebung (Integrated Development Environment, IDE) reduziert und ausgeblendet oder erweitert und angezeigt werden.

RegionStart
    : RegionStatement*
    ;

RegionStatement
    : RegionGroup
    | LogicalLine
    ;

RegionGroup
    : '#' 'Region' StringLiteral LineTerminator
      RegionStatement*
      '#' 'End' 'Region' LineTerminator
    ;

Regionen können geschachtelt werden. Regionsdirektiven sind besonders darauf spezialisiert, dass sie weder innerhalb eines Methodentexts beginnen noch beenden können, und sie müssen die Blockstruktur des Programms respektieren. Beispiel:

Module Test
#Region "Startup code - do not edit"
    Sub Main()
    End Sub
#End Region

End Module


' Error due to Region directives breaking the block structure
Class C
#Region "Fred"
End Class
#End Region

Externe Prüfsummenrichtlinien

Eine Quelldatei kann eine externe Prüfsummendirektive enthalten, die angibt, welche Prüfsumme für eine Datei ausgegeben werden soll, auf die in einer externen Quelldirektive verwiesen wird. In allen anderen Aspekten haben externe Quelldirektiven keine Auswirkungen auf die Kompilierung.

ExternalChecksumStart
    : ExternalChecksumStatement*
    ;

ExternalChecksumStatement
    : '#' 'ExternalChecksum' '('
      StringLiteral ',' StringLiteral ',' StringLiteral
      ')' LineTerminator
    ;

Eine externe Prüfsummendirektive enthält den Dateinamen der externen Datei, eine GUID (Globally Unique Identifier), die der Datei zugeordnet ist, und die Prüfsumme für die Datei. Die GUID wird als Zeichenfolgenkonstante des Formulars "{xx-xxxx-xxxx-xxxx-xxxx}" angegeben, wobei x eine hexadezimale Ziffer ist. Die Prüfsumme wird als Zeichenfolgenkonstante des Formulars "xxxx..." angegeben, wobei x eine hexadezimale Ziffer ist. Die Anzahl der Ziffern in einer Prüfsumme muss eine gerade Zahl sein.

Eine externe Datei kann mehrere externe Prüfsummendirektiven zugeordnet sein, vorausgesetzt, dass alle GUID- und Prüfsummenwerte exakt übereinstimmen. Wenn der Name der externen Datei mit dem Namen einer kompilierten Datei übereinstimmt, wird die Prüfsumme zugunsten der Prüfsummenberechnung des Compilers ignoriert.

Beispiel:

#ExternalChecksum("c:\wwwroot\inetpub\test.aspx", _
    "{12345678-1234-1234-1234-123456789abc}", _
    "1a2b3c4e5f617239a49b9a9c0391849d34950f923fab9484")

Module Test
    Sub Main()

#ExternalSource("c:\wwwroot\inetpub\test.aspx", 30)
        Console.WriteLine("In test.aspx")
#End ExternalSource

    End Sub
End Module