Diretivas de pré-processamento

Depois que um arquivo é analisado lexicamente, ocorrem vários tipos de pré-processamento de origem. A compilação condicional mais importante determina qual origem é processada pela gramática sintactica; dois outros tipos de diretivas, diretivas de origem externas e diretivas de região, fornecem metadados sobre a origem, mas não têm efeito na compilação.

Compilação condicional

A compilação condicional controla se sequências de linhas lógicas são convertidas em código real. No início da compilação condicional, todas as linhas lógicas estão habilitadas; no entanto, colocar linhas em instruções de compilação condicional pode desabilitar seletivamente essas linhas dentro do arquivo, fazendo com que elas sejam ignoradas durante o restante do processo de compilação.

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

Por exemplo, o programa

#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

produz exatamente a mesma sequência de tokens que o programa

Class C
    Sub F()
    End Sub

    Sub I()
    End Sub
End Class

As expressões constantes permitidas nas diretivas de compilação condicional são um subconjunto de expressões constantes gerais.

O pré-processador permite o espaço em branco e continuações de linha explícitas antes e depois de cada token.

Diretivas de constante condicional

Instruções constantes condicionais definem constantes que existem em um espaço de declaração de compilação condicional separado com escopo para o arquivo de origem.

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

O espaço de declaração é especial porque nenhuma declaração explícita de constantes de compilação condicional é necessária – constantes condicionais podem ser definidas implicitamente em uma diretiva de compilação condicional.

Antes de receber um valor, uma constante de compilação condicional tem o valor Nothing. Quando uma constante de compilação condicional recebe um valor, que deve ser uma expressão constante, o tipo da constante se torna o tipo do valor atribuído a ele. Uma constante de compilação condicional pode ser redefinida várias vezes em um arquivo de origem.

Por exemplo, o código a seguir imprime apenas a cadeia de caracteres about to print value e o valor de 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

O ambiente de compilação também pode definir constantes condicionais em um espaço de declaração de compilação condicional.

Diretivas de compilação condicional

As diretivas de compilação condicional controlam a compilação condicional.

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

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

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

Constantes condicionais só podem referenciar expressões constantes e constantes de compilação condicional. Cada uma das expressões constantes em um único grupo de compilação condicional é avaliada e convertida para o Boolean tipo em ordem textual de primeiro para último até que uma das expressões condicionais seja avaliada como True. Se uma expressão não for conversível, Booleanum erro de tempo de compilação resultará. A semântica permissiva e as comparações de cadeia de caracteres binárias são sempre usadas ao avaliar expressões constantes de compilação condicional, independentemente de quaisquer Option diretivas ou configurações de ambiente de compilação.

Todas as linhas delimitadas pelo grupo, incluindo diretivas de compilação condicional aninhadas, são desabilitadas, exceto por linhas entre a instrução que contém a True expressão e a próxima instrução condicional do grupo, ou linhas entre a Else instrução e a End If instrução, se aparecer Else no grupo e todas as expressões forem avaliadas como False.

Neste exemplo, a chamada para WriteToLog a Trace diretiva de compilação condicional não é processada porque a diretiva de compilação condicional ao redor Debug é Falseavaliada como .

#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

Diretivas de origem externa

Um arquivo de origem pode incluir diretivas de origem externas que indicam um mapeamento entre as linhas de origem e o texto externo à origem.

ESDStart
    : ExternalSourceStatement*
    ;

ExternalSourceStatement
    : ExternalSourceGroup
    | LogicalLine
    ;

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

As diretivas de origem externa não têm efeito na compilação e podem não estar aninhadas. Por exemplo:

Module Test
    Sub Main()

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

    End Sub
End Module

Diretivas de região

As diretivas de região agrupam linhas do código-fonte, mas não têm outro efeito na compilação. Todo o grupo pode ser recolhido e oculto, ou expandido e exibido, no IDE (ambiente de desenvolvimento integrado).

RegionStart
    : RegionStatement*
    ;

RegionStatement
    : RegionGroup
    | LogicalLine
    ;

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

As regiões podem estar aninhadas. As diretivas de região são especiais, pois não podem iniciar nem terminar dentro de um corpo do método e devem respeitar a estrutura de blocos do programa. Por exemplo:

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

Diretivas de soma de verificação externa

Um arquivo de origem pode incluir uma diretiva de soma de verificação externa que indica qual soma de verificação deve ser emitida para um arquivo referenciado em uma diretiva de origem externa. Em todos os outros aspectos, as diretivas de origem externas não têm efeito sobre a compilação.

ExternalChecksumStart
    : ExternalChecksumStatement*
    ;

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

Uma diretiva de soma de verificação externa contém o nome do arquivo externo, um GUID (identificador global exclusivo) associado ao arquivo e a soma de verificação do arquivo. O GUID é especificado como uma constante de cadeia de caracteres do formulário "{xxxxxxx-xxxx-xxxx-xxxx-xxxxx}", em que x é um dígito hexadecimal. A soma de verificação é especificada como uma constante de cadeia de caracteres do formulário "xxxx...", em que x é um dígito hexadecimal. O número de dígitos em uma soma de verificação deve ser um número par.

Um arquivo externo pode ter várias diretivas de soma de verificação externa associadas a ele, desde que todos os valores guid e soma de verificação correspondam exatamente. Se o nome do arquivo externo corresponder ao nome de um arquivo que está sendo compilado, a soma de verificação será ignorada em favor do cálculo da soma de verificação do compilador.

Por exemplo:

#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