Direktivy předběžného zpracování

Jakmile je soubor lexicky analyzován, dochází k několika druhům předběžného zpracování zdroje. Nejdůležitější podmíněná kompilace určuje, který zdroj je zpracován syntaktickou gramatikou; dva další typy direktiv – direktivy externího zdroje a direktivy oblastí – poskytují metainformace o zdroji, ale nemají žádný vliv na kompilaci.

Podmíněná kompilace

Podmíněná kompilace řídí, jestli jsou sekvence logických řádků přeloženy do skutečného kódu. Na začátku podmíněné kompilace jsou povoleny všechny logické řádky; Uzavření řádků v příkazech podmíněné kompilace však může selektivně zakázat tyto řádky v souboru, což způsobí, že budou ignorovány během zbytku procesu kompilace.

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 ')'
    ;

Například program

#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

vytvoří přesně stejnou sekvenci tokenů jako program.

Class C
    Sub F()
    End Sub

    Sub I()
    End Sub
End Class

Konstantní výrazy povolené ve direktivách podmíněné kompilace jsou podmnožinou obecných výrazů konstant.

Preprocesor umožňuje pokračování prázdných a explicitních řádků před a za každým tokenem.

Direktivy podmíněné konstanty

Podmíněné příkazy konstant definují konstanty, které existují v samostatném prostoru deklarace podmíněné kompilace vymezeném na zdrojový soubor.

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

Prostor deklarace je speciální v tom, že není nutná žádná explicitní deklarace konstant podmíněné kompilace – podmíněné konstanty lze implicitně definovat v direktivě podmíněné kompilace.

Před přiřazením hodnoty má konstanta podmíněné kompilace hodnotu Nothing. Pokud je podmíněná kompilační konstanta přiřazena hodnota, která musí být konstantní výraz, typ konstanty se stane typem hodnoty, která je k ní přiřazena. Konstanta podmíněné kompilace může být několikrát předdefinována ve zdrojovém souboru.

Například následující kód vytiskne pouze řetězec about to print value a hodnotu 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

Prostředí kompilace může také definovat podmíněné konstanty v prostoru deklarace podmíněné kompilace.

Direktivy podmíněné kompilace

Direktivy podmíněné kompilace řídí podmíněnou kompilaci.

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

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

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

Podmíněné konstanty mohou odkazovat pouze na konstantní výrazy a podmíněné kompilační konstanty. Každý z konstantních výrazů v rámci jedné skupiny podmíněné kompilace se vyhodnotí a převede na Boolean typ v textovém pořadí od prvního do posledního, dokud se jeden z podmíněných výrazů vyhodnotí jako True. Pokud výraz není konvertibilní na , dojde k Booleanchybě kompilace. Při vyhodnocování konstantních výrazů podmíněné kompilace se vždy používají permissivní sémantika a porovnání binárních řetězců bez ohledu na všechny Option direktivy nebo nastavení prostředí kompilace.

Všechny řádky uzavřené skupinou, včetně vnořených direktiv podmíněné kompilace, jsou zakázány s výjimkou řádků mezi příkazem obsahujícím True výraz a dalším podmíněným příkazem skupiny nebo řádky mezi Else příkazem a End If příkazem, pokud Else se objeví ve skupině a všechny výrazy jsou vyhodnoceny jako False.

V tomto příkladu WriteToLog není volání v direktivě Trace podmíněné kompilace zpracováno, protože okolní Debug podmíněná kompilace direktiva je vyhodnocena jako False.

#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

Direktivy externího zdroje

Zdrojový soubor může obsahovat direktivy externího zdroje, které označují mapování mezi zdrojovými řádky a textem externím zdrojem.

ESDStart
    : ExternalSourceStatement*
    ;

ExternalSourceStatement
    : ExternalSourceGroup
    | LogicalLine
    ;

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

Direktivy externího zdroje nemají žádný vliv na kompilaci a nemusí být vnořené. Například:

Module Test
    Sub Main()

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

    End Sub
End Module

Direktivy oblastí

Direktivy oblastí seskupují řádky zdrojového kódu, ale nemají žádný jiný vliv na kompilaci. Celá skupina může být sbalená a skrytá nebo rozbalená a zobrazená v integrovaném vývojovém prostředí (IDE).

RegionStart
    : RegionStatement*
    ;

RegionStatement
    : RegionGroup
    | LogicalLine
    ;

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

Oblasti můžou být vnořené. Direktivy oblastí jsou zvláštní v tom, že nemohou zahájit ani ukončit v rámci těla metody a musí respektovat blokovou strukturu programu. Například:

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

Direktivy externích kontrolních součtů

Zdrojový soubor může obsahovat externí direktivu kontrolního součtu, která indikuje, jaké kontrolní součty mají být generovány pro soubor odkazovaný v direktivě externího zdroje. Ve všech ostatních ohledech nemají direktivy externího zdroje žádný vliv na kompilaci.

ExternalChecksumStart
    : ExternalChecksumStatement*
    ;

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

Direktiva externího kontrolního součtu obsahuje název souboru externího souboru, globálně jedinečný identifikátor (GUID) přidružený k souboru a kontrolní součet souboru. Identifikátor GUID je zadán jako řetězcová konstanta formuláře {xxxxxxxx-xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}, kde x je šestnáctková číslice. Kontrolní součet se zadává jako řetězcová konstanta formuláře xxxx..., kde x je šestnáctková číslice. Počet číslic v kontrolním součtu musí být sudé číslo.

Externí soubor může mít přidružených více direktiv externích kontrolních součtů za předpokladu, že všechny hodnoty GUID a kontrolního součtu přesně odpovídají. Pokud název externího souboru odpovídá názvu kompilovaného souboru, kontrolní součet se ignoruje ve prospěch výpočtu kontrolního součtu kompilátoru.

Například:

#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