Sdílet prostřednictvím


Lexikální gramatika

Kompilace programu Jazyka Visual Basic nejprve zahrnuje překlad nezpracovaného datového proudu znaků Unicode do seřazené sady lexikálních tokenů. Vzhledem k tomu, že jazyk jazyka Visual Basic není volný formát, sada tokenů je pak dále rozdělena do řady logických řádků. Logická čára se nachází od začátku datového proudu nebo ukončovací čáry až po další ukončovací čáru, která není před pokračováním řádku nebo přes konec datového proudu.

Poznámka. Se zavedením výrazů literálů XML ve verzi 9.0 jazyka už Jazyk Visual Basic nemá odlišnou lexikální gramatiku v tom smyslu, že kód jazyka Visual Basic lze tokenizovat bez ohledu na syntaktický kontext. Důvodem je skutečnost, že XML a Visual Basic mají různá lexikální pravidla a sadu lexikálních pravidel, která se používají v každém konkrétním okamžiku, závisí na tom, jaká syntaktická konstrukce se v tuto chvíli zpracovává. Tato specifikace uchovává tuto lexikální gramatickou část jako vodítko k lexikálním pravidlům běžného kódu jazyka Visual Basic.

LogicalLineStart
    : LogicalLine*
    ;

LogicalLine
    : LogicalLineElement* Comment? LineTerminator
    ;

LogicalLineElement
    : WhiteSpace
    | LineContinuation
    | Token
    ;

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

Znaky a čáry

Programy jazyka Visual Basic se skládají z znaků sady znaků Unicode.

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

Ukončovací čáry

Znaky zalomení řádku unicode odděluje logické řádky.

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

Pokračování řádku

Pokračování řádku se skládá z alespoň jednoho prázdného znaku, který bezprostředně předchází jednomu podtržítku jako poslední znak (jiný než prázdné znaky) v řádku textu. Pokračování řádku umožňuje logické čáře přesahovat více než jednu fyzickou čáru. Pokračování čar se považuje za prázdné, i když nejsou.

LineContinuation
    : WhiteSpace '_' WhiteSpace* LineTerminator
    ;

Následující program ukazuje několik pokračování řádků:

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

Některá místa v syntaktické gramatikě umožňují implicitní pokračování řádků. Když dojde k ukončení řádku

  • za čárkou (,), levou závorkou ((), otevřenou složenou závorkou ({) nebo otevřeným vloženým výrazem (<%=)

  • po kvalifikátoru člena (. nebo .@...) za předpokladu, že se kvalifikuje něco (tj. nepoužívá implicitní With kontext).

  • před blízkou závorkou ()), zavřením složené závorky (}) nebo zavřením vloženého výrazu (%>)

  • za menší než (<) v kontextu atributu

  • před více než (>) v kontextu atributu

  • za atributem větší než (>) v kontextu atributu, který není na úrovni souboru

  • před a po operátorech dotazu (Where, Order, Select, atd.)

  • za binárními operátory (+, -, /, *atd.) v kontextu výrazu

  • po operátorech přiřazení (=, :=, +=, -=atd.) v libovolném kontextu.

ukončovací čára je považována za pokračování řádku.

Comma
    : ',' LineTerminator?
    ;

Period
    : '.' LineTerminator?
    ;

OpenParenthesis
    : '(' LineTerminator?
    ;

CloseParenthesis
    : LineTerminator? ')'
    ;

OpenCurlyBrace
    : '{' LineTerminator?
    ;

CloseCurlyBrace
    : LineTerminator? '}'
    ;

Equals
    : '=' LineTerminator?
    ;

ColonEquals
    : ':' '=' LineTerminator?
    ;

Například předchozí příklad může být také napsán takto:

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

Implicitní pokračování řádku bude odvozeno pouze přímo před nebo za zadaným tokenem. Nebudou odvozeny před pokračováním řádku ani po nich. Například:

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

y

Pokračování řádku nebudou odvozena v kontextech podmíněné kompilace. (Poznámka: Toto poslední omezení je povinné, protože text v blocích podmíněné kompilace, které nejsou kompilovány, nemusí být syntakticky platné. Text v bloku se tak může omylem "vyzvednout" příkazem podmíněné kompilace, zejména s tím, jak se jazyk rozšíří v budoucnu.)

Prázdné znaky

Prázdné znaky slouží pouze k oddělení tokenů a jinak se ignoruje. Logické čáry obsahující pouze prázdné znaky se ignorují. (Poznámka: Ukončovací čáry se nepovažují za prázdné znaky.)

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

Komentáře

Komentář začíná jedním znakem uvozovek nebo klíčovým slovem REM. Znak s jednou uvozovkou je buď znak jednoduché uvozovky ASCII, levý znak uvozovek Unicode, nebo znak s jednou uvozovkou v kódování Unicode. Komentáře můžou začínat kdekoli na zdrojovém řádku a konec fyzického řádku ukončí komentář. Kompilátor ignoruje znaky mezi začátkem komentáře a ukončovacím znakem řádku. Komentáře se proto nemohou rozšířit přes více řádků pomocí pokračování řádku.

Comment
    : CommentMarker Character*
    ;

CommentMarker
    : SingleQuoteCharacter
    | 'REM'
    ;

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

Identifikátory

Identifikátor je název. Identifikátory jazyka Visual Basic odpovídají standardní příloze Unicode 15 s jednou výjimkou: identifikátory mohou začínat znakem podtržítka (spojnice). Pokud identifikátor začíná podtržítkem, musí obsahovat alespoň jeden další platný znak identifikátoru, aby ho z pokračování řádku rozdobrazil.

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
    ;

Běžné identifikátory nemusí odpovídat klíčovým slovům, ale řídicí identifikátory nebo identifikátory s znakem typu mohou. Řídicí identifikátor je identifikátor oddělený hranatými závorkami. Řídicí identifikátory se řídí stejnými pravidly jako běžné identifikátory s tím rozdílem, že se můžou shodovat s klíčovými slovy a nemusí obsahovat znaky typu.

Tento příklad definuje třídu pojmenovanou class sdílenou metodou shared , která přebírá parametr s názvem boolean a pak volá metodu.

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

Identifikátory nerozlišují malá a velká písmena, takže dva identifikátory jsou považovány za stejný identifikátor, pokud se liší pouze v případě. (Poznámka: Mapování standardních případů 1:1 unicode se používají při porovnávání identifikátorů a všech mapování případů specifických pro národní prostředí se ignorují.)

Znaky typu

Znak typu označuje typ předchozího identifikátoru. Znak typu není považován za součást identifikátoru.

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

IntegerTypeCharacter
    : '%'
    ;

LongTypeCharacter
    : '&'
    ;

DecimalTypeCharacter
    : '@'
    ;

SingleTypeCharacter
    : '!'
    ;

DoubleTypeCharacter
    : '#'
    ;

StringTypeCharacter
    : '$'
    ;

Pokud deklarace obsahuje znak typu, musí znak typu souhlasit s typem zadaným v samotné deklaraci; v opačném případě dojde k chybě v době kompilace. Pokud deklarace vynechá typ (například pokud nezadáte As klauzuli), znak typu se implicitně nahradí jako typ deklarace.

Mezi identifikátorem a znakem jeho typu nesmí být žádné prázdné znaky. Neexistují žádné znaky typu pro Byte, , SByteUShortShort, UInteger nebo ULong, kvůli nedostatku vhodných znaků.

Připojení znaku typu k identifikátoru, který koncepčně nemá typ (například název oboru názvů) nebo identifikátor, jehož typ nesouhlasí s typem znaku typu, způsobí chybu v době kompilace.

Následující příklad ukazuje použití znaků typu:

' 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

Znak ! typu představuje zvláštní problém v tom, že jej lze použít jak jako znak typu, tak jako oddělovač v jazyce. Chcete-li odebrat nejednoznačnost, znak je znak typu, ! pokud znak, který následuje za ním, nemůže spustit identifikátor. Pokud ano, ! pak je znak oddělovačem, nikoli znakem typu.

Klíčová slova

Klíčové slovo je slovo, které má speciální význam v konstruktoru jazyka. Všechna klíčová slova jsou vyhrazena jazykem a nesmí být použita jako identifikátory, pokud nejsou identifikátory uchycené. (Poznámka.EndIf, , GoSub, VariantLeta Wend jsou zachovány jako klíčová slova, i když se již nepoužívají v jazyce 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'         
    ;

Literalové hodnoty

Literál je textová reprezentace konkrétní hodnoty typu. Mezi literály patří logická hodnota, celé číslo, plovoucí desetinná čárka, řetězec, znak a datum.

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

Logické literály

True a False jsou literály Boolean typu, který se mapuje na pravdivý a nepravdivý stav.

BooleanLiteral
    : 'True' | 'False'
    ;

Celočíselné literály

Celočíselné literály můžou být desítkové (základ 10), šestnáctkové (základ 16) nebo osmičkové (základ 8). Literál desítkového celého čísla je řetězec desetinných číslic (0–9). Šestnáctkový literál následuje &H řetězec šestnáctkových číslic (0-9, A-F). Osmičkový literál následuje &O řetězec osmičkových číslic (0-7). Desetinné literály přímo představují desetinnou hodnotu celočíselného literálu, zatímco osmičkové a šestnáctkové literály představují binární hodnotu celočíselného literálu (tedy &H8000S je -32768, nikoli chyba přetečení).

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

Typ literálu je určen jeho hodnotou nebo následujícím znakem typu. Pokud není zadán žádný znak typu, hodnoty v oblasti Integer typu jsou zadány jako Integer; hodnoty mimo oblast pro Integer jsou zadány jako Long. Pokud typ celočíselného literálu nemá dostatečnou velikost pro uložení celočíselného literálu, výsledkem chyby v době kompilace. (Poznámka: Neexistuje znak typu, Byte protože nejpřirozenější znak by byl B, což je právní znak v šestnáctkovém literálu.)

literály Floating-Point

Literál s plovoucí desetinnou čárkou je celočíselná literál následovaná nepovinnou desetinnou čárkou (znak tečky ASCII) a mantisou a volitelným exponentem základu 10. Ve výchozím nastavení je literál s plovoucí desetinou čárkou typu Double. Je-li Singlezadán znak , Doublenebo Decimal typ, literál je tohoto typu. Pokud je typ literálu s plovoucí desetinou čárkou nedostatečný k uložení literálu s plovoucí desetinou čárkou, dojde k chybě v době kompilace.

Poznámka. Stojí za zmínku Decimal , že datový typ může kódovat koncové nuly v hodnotě. Specifikace v současné době neobsahuje žádný komentář k tomu, zda by kompilátor měl respektovat koncové nuly v Decimal literálu.

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
    : '+'
    | '-'
    ;

Řetězcové literály

Řetězcový literál je posloupnost nula nebo více znaků Unicode začínajících a končících znakem dvojité uvozovky ASCII, znakem s dvojitou uvozovkou, znakem uvozovek zleva unicode nebo znakem uvozovek vpravo unicode. V řetězci je sekvence dvou dvojitých uvozovek řídicí sekvence představující dvojitou uvozovku v řetězci.

StringLiteral
    : DoubleQuoteCharacter StringCharacter* DoubleQuoteCharacter
    ;

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

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

Řetězcová konstanta je typu 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

Kompilátor může nahradit konstantní řetězcový výraz řetězcovým literálem. Každý řetězcový literál nemusí nezbytně vytvářet novou instanci řetězce. Pokud se ve stejném programu zobrazí dva nebo více řetězcových literálů, které jsou ekvivalentní podle operátoru rovnosti řetězců pomocí sémantiky binárního porovnání, mohou tyto řetězcové literály odkazovat na stejnou instanci řetězce. Výstup následujícího programu může například vrátit True , protože dva literály můžou odkazovat na stejnou instanci řetězce.

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

Literály znaků

Literál znaků představuje jeden znak Char Unicode typu. Dva znaky s dvojitými uvozovkami představují řídicí sekvenci představující znak dvojité uvozovky.

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

Literály data

Literál data představuje určitý moment v čase vyjádřený jako hodnota Date typu.

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

Literál může určovat datum i čas, pouze datum nebo jenom čas. Pokud je hodnota data vynechána, předpokládá se 1. leden roku 1 v gregoriánském kalendáři. Pokud je časová hodnota vynechána, předpokládá se 12:00:00.

Aby nedocházelo k problémům s interpretací hodnoty roku v hodnotě kalendářního data, nemůže být hodnota roku dvě číslice. Při vyjádření data v prvním století AD/CE je nutné zadat počáteční nuly.

Časovou hodnotu lze zadat buď pomocí hodnoty 24 hodin, nebo 12hodinové hodnoty; časové hodnoty, které vynechávají AM nebo PM se předpokládají, že jsou 24hodinové hodnoty. Pokud hodnota času vynechá minuty, literál 0 se použije ve výchozím nastavení. Pokud hodnota času vynechá sekundy, literál 0 se použije ve výchozím nastavení. Pokud jsou vynechány minuty i sekundy, pak AM nebo PM musí být zadány. Pokud zadaná hodnota data je mimo rozsah Date typu, dojde k chybě v době kompilace.

Následující příklad obsahuje několik literálů kalendářních dat.

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.

Nic

Nothing je zvláštní literál; nemá typ a je konvertibilní na všechny typy v systému typů, včetně parametrů typu. Při převodu na určitý typ je to ekvivalent výchozí hodnoty tohoto typu.

Nothing
    : 'Nothing'
    ;

Oddělovače

Následující znaky ASCII jsou oddělovače:

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

Znaky operátoru

Následující znaky nebo sekvence znaků ASCII označují operátory:

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