전처리 지시문

파일이 어휘적으로 분석되면 여러 종류의 원본 전처리가 발생합니다. 가장 중요한 조건부 컴파일은 구문 문법에 의해 처리되는 원본을 결정합니다. 외부 소스 지시문과 지역 지시문이라는 두 가지 다른 유형의 지시문은 원본에 대한 메타 정보를 제공하지만 컴파일에는 영향을 주지 않습니다.

조건부 컴파일

조건부 컴파일은 논리 줄 시퀀스가 실제 코드로 변환되는지 여부를 제어합니다. 조건부 컴파일이 시작될 때 모든 논리 줄이 활성화됩니다. 그러나 조건부 컴파일 문에 줄을 묶으면 파일 내에서 해당 줄을 선택적으로 사용하지 않도록 설정하여 나머지 컴파일 프로세스 중에 해당 줄이 무시될 수 있습니다.

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

예를 들어 프로그램

#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

는 프로그램과 정확히 동일한 토큰 시퀀스를 생성합니다.

Class C
    Sub F()
    End Sub

    Sub I()
    End Sub
End Class

조건부 컴파일 지시문에서 허용되는 상수 식은 일반 상수 식의 하위 집합입니다.

전처리기는 모든 토큰 전후에 공백 및 명시적 줄 연속을 허용합니다.

조건부 상수 지시문

조건부 상수 문은 소스 파일로 범위가 지정된 별도의 조건부 컴파일 선언 공간에 존재하는 상수를 정의합니다.

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

조건부 컴파일 상수에 대한 명시적 선언이 필요하지 않으며 조건부 컴파일 지시문에서 조건부 상수는 암시적으로 정의할 수 있으므로 선언 공간은 특별합니다.

값을 할당하기 전에 조건부 컴파일 상수에 값 Nothing이 있습니다. 조건부 컴파일 상수에 상수 식이어야 하는 값이 할당되면 상수의 형식이 할당되는 값의 형식이 됩니다. 조건부 컴파일 상수는 소스 파일 전체에서 여러 번 다시 정의될 수 있습니다.

예를 들어 다음 코드는 문자열 about to print value 과 값 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

컴파일 환경은 조건부 컴파일 선언 공간에서 조건부 상수도 정의할 수 있습니다.

조건부 컴파일 지시문

조건부 컴파일 지시문은 조건부 컴파일을 제어합니다.

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

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

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

조건부 상수는 상수 식과 조건부 컴파일 상수만 참조할 수 있습니다. 단일 조건부 컴파일 그룹 내의 각 상수 식이 계산되고 조건식 중 하나가 계산될 때까지 텍스트 순서로 형식으로 변환 Boolean 됩니다 True. 식을 변환할 수 Boolean없는 경우 컴파일 시간 오류가 발생합니다. 허용되는 의미 체계 및 이진 문자열 비교는 지시문 또는 컴파일 환경 설정에 관계없이 Option 조건부 컴파일 상수 식을 평가할 때 항상 사용됩니다.

중첩된 조건부 컴파일 지시문을 포함하여 그룹으로 묶인 모든 줄은 식을 포함하는 True 문과 그룹의 다음 조건문 사이의 줄 또는 그룹에 나타나고 모든 식이 계산False되는 경우 Else 문과 End If 문 사이의 Else 줄을 제외하고 비활성화됩니다.

이 예제에서는 주변 Debug 조건부 컴파일 지시문이 계산False되기 때문에 조건부 컴파일 지시문의 호출 WriteToLogTrace 이 처리되지 않습니다.

#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

외부 원본 지시문

원본 파일에는 원본 줄과 원본 외부 텍스트 간의 매핑을 나타내는 외부 소스 지시문이 포함될 수 있습니다.

ESDStart
    : ExternalSourceStatement*
    ;

ExternalSourceStatement
    : ExternalSourceGroup
    | LogicalLine
    ;

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

외부 소스 지시문은 컴파일에 영향을 주지 않으며 중첩되지 않을 수 있습니다. 다음은 그 예입니다.

Module Test
    Sub Main()

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

    End Sub
End Module

지역 지시문

지역 지시문은 소스 코드 줄을 그룹화하지만 컴파일에는 다른 영향을 주지 않습니다. IDE(통합 개발 환경)에서 전체 그룹을 축소 및 숨기거나 확장 및 볼 수 있습니다.

RegionStart
    : RegionStatement*
    ;

RegionStatement
    : RegionGroup
    | LogicalLine
    ;

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

영역은 중첩될 수 있습니다. 영역 지시문은 메서드 본문 내에서 시작하거나 종료할 수 없으며 프로그램의 블록 구조를 준수해야 한다는 점에서 특별합니다. 다음은 그 예입니다.

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

외부 체크섬 지시문

원본 파일에는 외부 소스 지시문에서 참조되는 파일에 대해 내보내야 하는 체크섬을 나타내는 외부 체크섬 지시문이 포함될 수 있습니다. 다른 모든 측면에서 외부 소스 지시문은 컴파일에 영향을 주지 않습니다.

ExternalChecksumStart
    : ExternalChecksumStatement*
    ;

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

외부 체크섬 지시문에는 외부 파일의 파일 이름, 파일과 연결된 GUID(Globally Unique Identifier) 및 파일에 대한 체크섬이 포함됩니다. GUID는 "{xxxxxxxx-xxxx-xxxx-xxxx-xxxx-xxxxxx}" 형식의 문자열 상수로 지정됩니다. 여기서 x는 16진수입니다. 체크섬은 "xxxx..."형식의 문자열 상수로 지정됩니다. 여기서 x는 16진수입니다. 체크섬의 숫자 수는 짝수여야 합니다.

모든 GUID 및 체크섬 값이 정확하게 일치하는 경우 외부 파일에는 여러 개의 외부 체크섬 지시문이 연결되어 있을 수 있습니다. 외부 파일의 이름이 컴파일되는 파일의 이름과 일치하면 컴파일러의 체크섬 계산을 위해 체크섬이 무시됩니다.

다음은 그 예입니다.

#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