词法语法

首先编译 Visual Basic 程序涉及将 Unicode 字符的原始流转换为有序的词法标记集。 由于 Visual Basic 语言不是自由格式,因此标记集随后进一步划分为一系列逻辑行。 逻辑行跨越从流的开头或行终止符到下一行终止符,该终止符前面不是行延续或流末尾。

注意。 随着语言版本 9.0 中的 XML 文本表达式的引入,Visual Basic 不再具有不同的词法语法,因为 Visual Basic 代码可以在不考虑语法上下文的情况下进行标记化。 这是因为 XML 和 Visual Basic 具有不同的词法规则,并且在任何特定时间使用的词法规则集取决于当前正在处理哪种语法构造。 此规范保留此词法语法部分,作为常规 Visual Basic 代码词法规则的指南。

LogicalLineStart
    : LogicalLine*
    ;

LogicalLine
    : LogicalLineElement* Comment? LineTerminator
    ;

LogicalLineElement
    : WhiteSpace
    | LineContinuation
    | Token
    ;

Token
    : Identifier
    | Keyword
    | Literal
    | Separator
    | Operator
    ;

字符和行

Visual Basic 程序由 Unicode 字符集中的字符组成。

Character:
    '<Any Unicode character except a LineTerminator>'
    ;

行终止符

Unicode 换行符分隔逻辑行。

LineTerminator
    : '<Unicode 0x00D>'
    | '<Unicode 0x00A>'
    | '<CR>'
    | '<LF>'
    | '<Unicode 0x2028>'
    | '<Unicode 0x2029>'
    ;

续行符

行延续包含至少一个空格字符,该字符紧接在单个下划线字符前面,作为文本行中的最后一个字符(空格以外的)。 行延续允许逻辑行跨越多个物理行。 行延续被视为空白,即使它们不是空格。

LineContinuation
    : WhiteSpace '_' WhiteSpace* LineTerminator
    ;

以下程序显示了一些行延续:

Module Test
    Sub Print( _
        Param1 As Integer, _
        Param2 As Integer )

        If (Param1 < Param2) Or _
            (Param1 > Param2) Then
            Console.WriteLine("Not equal")
        End If
    End Function
End Module

语法中的某些位置允许 隐式行延续。 遇到行终止符时

  • 在逗号()、左括号(,()、左大括号()或打开嵌入表达式后({<%=

  • 在成员限定符(..@...)之后,前提是某个内容被限定(即未使用隐式 With 上下文)

  • 在右括号前()、右大括号()})或关闭嵌入表达式(%>

  • 在属性上下文中小于 (<) 之后

  • 在属性上下文中大于 (>) 之前

  • 在非文件级属性上下文中大于 (>) 之后

  • 查询运算符前后(WhereOrderSelect

  • 表达式上下文中的二元运算符(+-/*等)之后

  • 在任何上下文中赋值运算符(=:=+=-=等)之后。

行终止符被视为行延续。

Comma
    : ',' LineTerminator?
    ;

Period
    : '.' LineTerminator?
    ;

OpenParenthesis
    : '(' LineTerminator?
    ;

CloseParenthesis
    : LineTerminator? ')'
    ;

OpenCurlyBrace
    : '{' LineTerminator?
    ;

CloseCurlyBrace
    : LineTerminator? '}'
    ;

Equals
    : '=' LineTerminator?
    ;

ColonEquals
    : ':' '=' LineTerminator?
    ;

例如,上一个示例也可以编写为:

Module Test
    Sub Print(
        Param1 As Integer,
        Param2 As Integer)

        If (Param1 < Param2) Or
            (Param1 > Param2) Then
            Console.WriteLine("Not equal")
        End If
    End Function
End Module

仅在指定标记之前或之后直接推断隐式行延续。 它们不会在行延续之前或之后推断。 例如:

Dim y = 10
' Error: Expression expected for assignment to x
Dim x = _

y

行延续不会在条件编译上下文中推断。 (注意。 此最后一个限制是必需的,因为未编译的条件编译块中的文本不必语法有效。因此,块中的文本可能会意外地被条件编译语句“拾取”,尤其是在语言在将来扩展时。

空格

空格 仅用于分隔令牌,否则将被忽略。 仅包含空格的逻辑行将被忽略。 (注意。 行终止符不被视为空格。

WhiteSpace
    : '<Unicode class Zs>'
    | '<Unicode Tab 0x0009>'
    ;

注释

注释以单引号字符或关键字REM开头。 单引号字符是 ASCII 单引号字符、Unicode 左单引号字符或 Unicode 右单引号字符。 批注可以在源行的任意位置开始,物理行的末尾结束批注。 编译器忽略注释开头和行终止符之间的字符。 因此,注释不能使用行延续跨多行扩展。

Comment
    : CommentMarker Character*
    ;

CommentMarker
    : SingleQuoteCharacter
    | 'REM'
    ;

SingleQuoteCharacter
    : '\''
    | '<Unicode 0x2018>'
    | '<Unicode 0x2019>'
    ;

标识符

标识符是一个名称。 Visual Basic 标识符符合 Unicode 标准附件 15,但有一个例外:标识符可能以下划线(连接器)字符开头。 如果标识符以下划线开头,则它必须包含至少一个有效的标识符字符,才能将其与行延续区分开来。

Identifier
    : NonEscapedIdentifier TypeCharacter?
    | Keyword TypeCharacter
    | EscapedIdentifier
    ;

NonEscapedIdentifier
    : '<Any IdentifierName but not Keyword>'
    ;

EscapedIdentifier
    : '[' IdentifierName ']'
    ;

IdentifierName
    : IdentifierStart IdentifierCharacter*
    ;

IdentifierStart
    : AlphaCharacter
    | UnderscoreCharacter IdentifierCharacter
    ;

IdentifierCharacter
    : UnderscoreCharacter
    | AlphaCharacter
    | NumericCharacter
    | CombiningCharacter
    | FormattingCharacter
    ;

AlphaCharacter
    : '<Unicode classes Lu,Ll,Lt,Lm,Lo,Nl>'
    ;

NumericCharacter
    : '<Unicode decimal digit class Nd>'
    ;

CombiningCharacter
    : '<Unicode combining character classes Mn, Mc>'
    ;

FormattingCharacter
    : '<Unicode formatting character class Cf>'
    ;

UnderscoreCharacter
    : '<Unicode connection character class Pc>'
    ;

IdentifierOrKeyword
    : Identifier
    | Keyword
    ;

常规标识符可能与关键字不匹配,但具有类型字符的转义标识符或标识符可以。 转义标识符是由方括号分隔的标识符。 转义标识符遵循与常规标识符相同的规则,不同之处在于它们可能与关键字匹配,并且可能没有类型字符。

此示例定义一个类,该类使用名为 的共享方法命名 ,该类采用名为 /a0> 的参数,然后调用该方法。

Class [class]
    Shared Sub [shared]([boolean] As Boolean)
        If [boolean] Then
            Console.WriteLine("true")
        Else
            Console.WriteLine("false")
        End If
    End Sub
End Class

Module [module]
    Sub Main()
        [class].[shared](True)
    End Sub
End Module

标识符不区分大小写,因此,如果标识符仅在大小写时不同,则两个标识符被视为同一标识符。 (注意。 比较标识符和任何特定于区域设置的事例映射时,将使用 Unicode 标准一对一事例映射。

类型字符

类型字符表示上述标识符的类型。 类型字符不被视为标识符的一部分。

TypeCharacter
    : IntegerTypeCharacter
    | LongTypeCharacter
    | DecimalTypeCharacter
    | SingleTypeCharacter
    | DoubleTypeCharacter
    | StringTypeCharacter
    ;

IntegerTypeCharacter
    : '%'
    ;

LongTypeCharacter
    : '&'
    ;

DecimalTypeCharacter
    : '@'
    ;

SingleTypeCharacter
    : '!'
    ;

DoubleTypeCharacter
    : '#'
    ;

StringTypeCharacter
    : '$'
    ;

如果声明包含类型字符,则类型字符必须与声明本身中指定的类型一致;否则,将发生编译时错误。 如果声明省略类型(例如,如果未指定 As 子句),则类型字符将隐式替换为声明的类型。

标识符与其类型字符之间没有空格。 由于缺少合适的字符,因此没有类型ByteUIntegerSByteUShortShortULong字符。

将类型字符追加到概念上没有类型(例如命名空间名称)的标识符或类型与类型字符类型不符的标识符会导致编译时错误。

以下示例演示类型字符的使用:

' The follow line will cause an error: standard modules have no type.
Module Test1#
End Module

Module Test2

    ' This function takes a Long parameter and returns a String.
    Function Func$(Param&)

        ' The following line causes an error because the type character
        ' conflicts with the declared type of Func and Param.
        Func# = CStr(Param@)

        ' The following line is valid.
        Func$ = CStr(Param&)
    End Function
End Module

类型字符 ! 存在特殊问题,因为它既可用作类型字符,又可用作语言中的分隔符。 若要删除歧义,只要后面的字符无法启动标识符, ! 字符就是一个类型字符。 如果可以,则 ! 字符是分隔符,而不是类型字符。

关键字

关键字是语言构造中具有特殊含义的单词。 所有关键字均由语言保留,除非转义标识符,否则不能用作标识符。 (注意.EndIf、、LetGoSub、和VariantWend保留为关键字,尽管它们不再在 Visual Basic 中使用。

Keyword
    : 'AddHandler'      | 'AddressOf'      | 'Alias'       | 'And'
    | 'AndAlso'         | 'As'             | 'Boolean'     | 'ByRef'
	| 'Byte'            | 'ByVal'          | 'Call'        | 'Case'        
	| 'Catch'           | 'CBool'          | 'CByte'       | 'CChar'       
	| 'CDate'           | 'CDbl'           | 'CDec'        | 'Char'        
	| 'CInt'            | 'Class'          | 'CLng'        | 'CObj'        
	| 'Const'           | 'Continue'       | 'CSByte'      | 'CShort'      
	| 'CSng'            | 'CStr'           | 'CType'       | 'CUInt'       
	| 'CULng'           | 'CUShort'        | 'Date'        | 'Decimal'     
	| 'Declare'         | 'Default'        | 'Delegate'    | 'Dim'         
	| 'DirectCast'      | 'Do'             | 'Double'      | 'Each'        
	| 'Else'            | 'ElseIf'         | 'End'         | 'EndIf'       
	| 'Enum'            | 'Erase'          | 'Error'       | 'Event'       
	| 'Exit'            | 'False'          | 'Finally'     | 'For'         
	| 'Friend'          | 'Function'       | 'Get'         | 'GetType'     
	| 'GetXmlNamespace' | 'Global'         | 'GoSub'       | 'GoTo'        
	| 'Handles'         | 'If'             | 'Implements'  | 'Imports'     
	| 'In'              | 'Inherits'       | 'Integer'     | 'Interface'   
	| 'Is'              | 'IsNot'          | 'Let'         | 'Lib'         
	| 'Like'            | 'Long'           | 'Loop'        | 'Me'          
	| 'Mod'             | 'Module'         | 'MustInherit' | 'MustOverride'
	| 'MyBase'          | 'MyClass'        | 'Namespace'   | 'Narrowing'   
	| 'New'             | 'Next'           | 'Not'         | 'Nothing'     
	| 'NotInheritable'  | 'NotOverridable' | 'Object'      | 'Of'          
	| 'On'              | 'Operator'       | 'Option'      | 'Optional'    
	| 'Or'              | 'OrElse'         | 'Overloads'   | 'Overridable' 
	| 'Overrides'       | 'ParamArray'     | 'Partial'     | 'Private'     
	| 'Property'        | 'Protected'      | 'Public'      | 'RaiseEvent'  
	| 'ReadOnly'        | 'ReDim'          | 'REM'         | 'RemoveHandler'
	| 'Resume'          | 'Return'         | 'SByte'       | 'Select'      
	| 'Set'             | 'Shadows'        | 'Shared'      | 'Short'       
	| 'Single'          | 'Static'         | 'Step'        | 'Stop'        
	| 'String'          | 'Structure'      | 'Sub'         | 'SyncLock'    
	| 'Then'            | 'Throw'          | 'To'          | 'True'        
	| 'Try'             | 'TryCast'        | 'TypeOf'      | 'UInteger'    
	| 'ULong'           | 'UShort'         | 'Using'       | 'Variant'     
	| 'Wend'            | 'When'           | 'While'       | 'Widening'    
	| 'With'            | 'WithEvents'     | 'WriteOnly'   | 'Xor'         
    ;

文本

文本是类型特定值的文本表示形式。 文本类型包括布尔值、整数、浮点、字符串、字符和日期。

Literal
    : BooleanLiteral
    | IntegerLiteral
    | FloatingPointLiteral
    | StringLiteral
    | CharacterLiteral
    | DateLiteral
    | Nothing
    ;

布尔文本值

TrueFalse 分别映射到 true 和 false 状态的类型的文本 Boolean

BooleanLiteral
    : 'True' | 'False'
    ;

整数文本

整数文本可以是十进制(base 10)、十六进制(base 16)或八进制(base 8)。 十进制整数文本是十进制数字(0-9)的字符串。 十六进制文本 &H 后跟十六进制数字字符串(0-9,A-F)。 八进制文字 &O 后跟八进制数字字符串(0-7)。 小数文本直接表示整型文本的十进制值,而八进制和十六进制文本表示整数文本的二进制值(因此 &H8000S ,为 -32768,而不是溢出错误)。

IntegerLiteral
    : IntegralLiteralValue IntegralTypeCharacter?
    ;

IntegralLiteralValue
    : IntLiteral
    | HexLiteral
    | OctalLiteral
    ;

IntegralTypeCharacter
    : ShortCharacter
    | UnsignedShortCharacter
    | IntegerCharacter
    | UnsignedIntegerCharacter
    | LongCharacter
    | UnsignedLongCharacter
    | IntegerTypeCharacter
    | LongTypeCharacter
    ;

ShortCharacter
    : 'S'
    ;

UnsignedShortCharacter
    : 'US'
    ;

IntegerCharacter
    : 'I'
    ;

UnsignedIntegerCharacter
    : 'UI'
    ;

LongCharacter
    : 'L'
    ;

UnsignedLongCharacter
    : 'UL'
    ;

IntLiteral
    : Digit+
    ;

HexLiteral
    : '&' 'H' HexDigit+
    ;

OctalLiteral
    : '&' 'O' OctalDigit+
    ;

Digit
    : '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
    ;

HexDigit
    : '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
    | 'A' | 'B' | 'C' | 'D' | 'E' | 'F'
    ;

OctalDigit
    : '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7'
    ;

文本的类型由其值或以下类型字符确定。 如果未指定类型字符,则类型范围内的 Integer 值将键入为 Integer;超出范围 Integer 的值被键入为 Long。 如果整数文本的类型大小不足,无法容纳整数文本,则编译时错误结果。 (注意。 没有类型字符, Byte 因为最自然的字符是 B,这是十六进制文本中的法律字符。

Floating-Point 文本

浮点文本是一个整数文本,后跟一个可选的小数点(ASCII 句点字符)和 mantissa,以及可选的基数 10 指数。 默认情况下,浮点文本的类型 Double为 。 如果指定了 Single类型 Double字符或 Decimal 类型字符,则文本为该类型。 如果浮点文本的类型的大小不足,无法容纳浮点文本,则编译时错误将产生。

注意。 值得注意的是, Decimal 数据类型可以在值中对尾随零进行编码。 目前,该规范不对编译器是否应遵循文本尾 Decimal 随零发表评论。

FloatingPointLiteral
    : FloatingPointLiteralValue FloatingPointTypeCharacter?
    | IntLiteral FloatingPointTypeCharacter
    ;

FloatingPointTypeCharacter
    : SingleCharacter
    | DoubleCharacter
    | DecimalCharacter
    | SingleTypeCharacter
    | DoubleTypeCharacter
    | DecimalTypeCharacter
    ;

SingleCharacter
    : 'F'
    ;

DoubleCharacter
    : 'R'
    ;

DecimalCharacter
    : 'D'
    ;

FloatingPointLiteralValue
    : IntLiteral '.' IntLiteral Exponent?
    | '.' IntLiteral Exponent?
    | IntLiteral Exponent
    ;

Exponent
    : 'E' Sign? IntLiteral
    ;

Sign
    : '+'
    | '-'
    ;

字符串文本

字符串文本是以 ASCII 双引号字符、Unicode 左双引号字符或 Unicode 右双引号字符开头和结尾的 Unicode 字符序列。 在字符串中,两个双引号字符的序列是一个转义序列,表示字符串中的双引号。

StringLiteral
    : DoubleQuoteCharacter StringCharacter* DoubleQuoteCharacter
    ;

DoubleQuoteCharacter
    : '"'
    | '<unicode left double-quote 0x201c>'
    | '<unicode right double-quote 0x201D>'
    ;

StringCharacter
    : '<Any character except DoubleQuoteCharacter>'
    | DoubleQuoteCharacter DoubleQuoteCharacter
    ;

字符串常量的类型 String

Module Test
    Sub Main()

        ' This prints out: ".
        Console.WriteLine("""")

        ' This prints out: a"b.
        Console.WriteLine("a""b")

        ' This causes a compile error due to mismatched double-quotes.
        Console.WriteLine("a"b")
    End Sub
End Module

允许编译器将常量字符串表达式替换为字符串文本。 每个字符串文本不一定会导致新的字符串实例。 当使用二进制比较语义的字符串相等运算符的两个或多个字符串文本出现在同一程序中时,这些字符串文本可能引用相同的字符串实例。 例如,以下程序的输出可能会返回 True ,因为两个文本可能引用相同的字符串实例。

Module Test
    Sub Main()
        Dim a As Object = "he" & "llo"
        Dim b As Object = "hello"
        Console.WriteLine(a Is b)
    End Sub
End Module

字符文本

字符文本表示类型的 Char 单个 Unicode 字符。 两个双引号字符是表示双引号字符的转义序列。

CharacterLiteral
    : DoubleQuoteCharacter StringCharacter DoubleQuoteCharacter 'C'
    ;
Module Test
    Sub Main()

        ' This prints out: a.
        Console.WriteLine("a"c)

        ' This prints out: ".
        Console.WriteLine(""""c)
    End Sub
End Module

日期文本

日期文本表示以类型值 Date 表示的特定时间刻度。

DateLiteral
    : '#' WhiteSpace* DateOrTime WhiteSpace* '#'
    ;

DateOrTime
    : DateValue WhiteSpace+ TimeValue
    | DateValue
    | TimeValue
    ;

DateValue
    : MonthValue '/' DayValue '/' YearValue
    | MonthValue '-' DayValue '-' YearValue
    ;

TimeValue
    : HourValue ':' MinuteValue ( ':' SecondValue )? WhiteSpace* AMPM?
    | HourValue WhiteSpace* AMPM
    ;

MonthValue
    : IntLiteral
    ;

DayValue
    : IntLiteral
    ;

YearValue
    : IntLiteral
    ;

HourValue
    : IntLiteral
    ;

MinuteValue
    : IntLiteral
    ;

SecondValue
    : IntLiteral
    ;

AMPM
    : 'AM' | 'PM'
    ;    

文本可以同时指定日期和时间、日期或时间。 如果省略日期值,则假定公历中的第 1 年 1 月 1 日。 如果省略时间值,则假定上午 12:00:00。

为了避免在日期值中解释年份值时出现问题,年份值不能为两位数。 在一个世纪 AD/CE 中表示日期时,必须指定前导零。

可以使用 24 小时值或 12 小时值指定时间值;省略 AMPM 假定为 24 小时值的时间值。 如果时间值省略分钟数,则默认使用文本 0 。 如果时间值省略秒,则默认使用文本 0 。 如果省略分钟和秒,则必须 AM 指定或 PM 必须指定。 如果指定的日期值超出类型范围 Date ,则会发生编译时错误。

以下示例包含多个日期文本。

Dim d As Date

d = # 8/23/1970 3:45:39AM #
d = # 8/23/1970 #              ' Date value: 8/23/1970 12:00:00AM.
d = # 3:45:39AM #              ' Date value: 1/1/1 3:45:39AM.
d = # 3:45:39 #                ' Date value: 1/1/1 3:45:39AM.
d = # 13:45:39 #               ' Date value: 1/1/1 1:45:39PM.
d = # 1AM #                    ' Date value: 1/1/1 1:00:00AM.
d = # 13:45:39PM #             ' This date value is not valid.

Nothing 是一个特殊文字;它没有类型,并且可转换为类型系统中的所有类型的类型,包括类型参数。 转换为特定类型时,它等效于该类型的默认值。

Nothing
    : 'Nothing'
    ;

分隔符

以下 ASCII 字符是分隔符:

Separator
    : '(' | ')' | '{' | '}' | '!' | '#' | ',' | '.' | ':' | '?'
    ;

运算符字符

以下 ASCII 字符或字符序列表示运算符:

Operator
    : '&' | '*' | '+' | '-' | '/' | '\\' | '^' | '<' | '=' | '>'
    ;