어휘 구조

어휘 구조 (Lexical)

D 언어는 소스 코드를 읽는 과정부터 독특한 설계를 갖고 있어요. Lexical(어휘) 챕터는 바로 이 최초의 단계 — 원문 텍스트를 토큰(token)으로 쪼개는 규칙 — 을 다루는 부분이에요. 컴파일러가 코드를 이해하는 첫 번째 문턱이니까, 나중에 문법(syntax)이나 의미(semantics)를 배울 때 뼈대가 된다고 생각하면 돼요. 여기서는 코드가 어떻게 인코딩되고, 주석은 어떻게 처리되며, 문자열·숫자 리터럴이 어떻게 생겨먹는지까지 차근차근 설명할게요.

출처: https://dlang.org/spec/lex.html

본문

서론

어휘 분석(lexical analysis)은 구문 분석(syntax parsing)이나 의미 분석(semantic analysis)과 독립적으로 동작해요. 어휘 분석기는 소스 텍스트를 토큰들로 쪼개죠. 이 장에서 설명하는 어휘 문법(lexical grammar) 은 바로 그 토큰들의 문법이에요. 이 문법은 고속 스캐닝에 적합하도록, 그리고 올바른 스캐너 구현을 쉽게 만들도록 설계되었어요. 그래서 특수 케이스 규칙이 최소한이고, 번역 단계(phase)도 하나뿐이죠.

소스 텍스트 (Source Text)

소스 파일의 구조는 이런 식이에요:

SourceFile:
    ByteOrderMark Moduleopt
    Shebang Moduleopt
    Moduleopt
ByteOrderMark:
    \uFEFF

Shebang:
    #! Charactersopt EndOfShebang

EndOfShebang:
    \u000A
    EndOfFile

소스 텍스트는 다음 중 어떤 인코딩으로든 작성될 수 있어요:

  • ASCII (엄밀히 말하면 7-bit ASCII)
  • UTF-8
  • UTF-16BE
  • UTF-16LE
  • UTF-32BE
  • UTF-32LE

소스 텍스트 시작 부분에는 다음 UTF BOM(Byte Order Mark) 중 하나가 올 수 있어요:

UTF Byte Order Marks

Format BOM
UTF-8 EF BB BF
UTF-16BE FE FF
UTF-16LE FF FE
UTF-32BE 00 00 FE FF
UTF-32LE FF FE 00 00
ASCII BOM 없음

만약 소스 파일이 BOM으로 시작하지 않는다면, 첫 번째 문자가 반드시 U+0000007F 이하여야 해요.

소스 텍스트는 원래 표현(source representation)에서 Unicode 문자(Characters) 로 디코딩돼요. 그리고 그 문자들은 다시 WhiteSpace, EndOfLine, Comments, SpecialTokenSequences, Tokens로 나뉘고, 소스는 EndOfFile로 끝나요.

토큰 분리에는 maximal munch(가장 긴 토큰 우선) 알고리즘이 적용돼요. 즉, 어휘 분석기는 가능한 가장 긴 토큰을 가정한다는 뜻이에요. 예를 들어 >>는 두 개의 greater-than 토큰이 아니라 하나의 right-shift 토큰으로 취급되죠. 이 규칙에는 예외가 두 개 있어요:

  • 두 개의 부동소수점 리터럴처럼 보이는 것 사이에 끼어 있는 .., 예를 들면 1..2는, 마치 ..가 첫 정수와 공백으로 분리되어 있는 것처럼 해석돼요.
  • 1.a1, ., a 세 개의 토큰으로 해석되는 반면, 1. a1.a 두 개의 토큰으로 해석돼요.

문자 집합 (Character Set)

Character:
    any Unicode character

파일의 끝 (End of File)

EndOfFile:
    physical end of the file
    \u0000
    \u001A

소스 텍스트는 다음 중 먼저 오는 것으로 종료돼요: 물리적인 파일 끝, \u0000, 또는 \u001A.

줄의 끝 (End of Line)

EndOfLine:
    \u000D
    \u000A
    \u000D \u000A
    \u2028
    \u2029
    EndOfFile

공백 (White Space)

WhiteSpace:
    Space
    Space WhiteSpace

Space:
    \u0020
    \u0009
    \u000B
    \u000C

주석 (Comments)

Comment:
    BlockComment
    LineComment
    NestingBlockComment

BlockComment:
    /* Charactersopt */

LineComment:
    // Charactersopt EndOfLine

NestingBlockComment:
    /+ NestingBlockCommentCharactersopt +/

NestingBlockCommentCharacters:
    NestingBlockCommentCharacter
    NestingBlockCommentCharacter NestingBlockCommentCharacters

NestingBlockCommentCharacter:
    Character
    NestingBlockComment

Characters:
    Character
    Character Characters

D에는 세 종류의 주석이 있어요:

  1. 블록 주석(Block comment) — 여러 줄에 걸칠 수 있지만, 중첩(nest)되지는 않아요.
  2. 줄 주석(Line comment) — 줄의 끝에서 끝나요.
  3. 중첩 블록 주석(Nesting block comment) — 여러 줄에 걸칠 수 있고 중첩도 가능해요.

문자열과 주석의 내용은 토큰화되지 않아요. 그래서 문자열 안에 나타나는 주석 시작 기호는 주석을 시작시키지 않고, 주석 안의 문자열 구분자도 주석 종료/중첩 /+ 시작을 인식하는 데 영향을 주지 않아요. 단, /+ 주석 안에서 나타나는 /+를 제외하면, 주석 안의 주석 시작 기호는 무시돼요.

a = /+ // +/ 1;    // parses as if 'a = 1;'
a = /+ "+/" +/ 1"; // parses as if 'a = " +/ 1";'
a = /+ /* +/ */ 3; // parses as if 'a = */ 3;'

주석은 토큰 연결자(token concatenator)로 쓸 수 없어요. 예를 들어 abc/**/defabcdef라는 두 개의 토큰이지, abcdef라는 한 개의 토큰이 아니에요.

토큰 (Tokens)

Tokens:
    Token
    Token Tokens

Token:
    {
    }
    TokenNoBraces

TokenNoBraces:
    Identifier
    StringLiteral
    InterpolationExpressionSequence
    CharacterLiteral
    IntegerLiteral
    FloatLiteral
    Keyword
    /
    /=
    .
    ..
    ...
    &
    &=
    &&
    |
    |=
    ||
    -
    -=
    --
    +
    +=
    ++
    <
    <=
    <<
    <<=
    >
    >=
    >>=
    >>>=
    >>
    >>>
    !
    !=
    (
    )
    [
    ]
    ?
    ,
    ;
    :
    $
    =
    ==
    *
    *=
    %
    %=
    ^
    ^=
    ^^
    ^^=
    ~
    ~=
    @
    =>

식별자 (Identifiers)

Identifier:
    IdentifierStart
    IdentifierStart IdentifierChars

IdentifierChars:
    IdentifierChar
    IdentifierChar IdentifierChars

IdentifierStart:
    _
    Letter
    UniversalAlpha

IdentifierChar:
    IdentifierStart
    0
    NonZeroDigit

식별자는 문자(letter), _, 또는 universal alpha로 시작하고, 그 뒤에 문자·_·숫자·universal alpha가 몇 개든 이어질 수 있어요. universal alpha는 C99 표준의 ISO/IEC 9899:1999(E) 부록 D에 정의된 것을 따르고요. 식별자는 길이에 제한이 없고, 대소문자를 구분해요.

구현 정의(Implementation Defined):

__(밑줄 두 개)로 시작하는 식별자는 예약되어 있어요.

문자열 리터럴 (String Literals)

StringLiteral:
    WysiwygString
    AlternateWysiwygString
    DoubleQuotedString
    DelimitedString
    TokenString
    HexString

문자열 리터럴은 wysiwyg 문자열, 이중 따옴표(double quoted) 문자열, delimited 문자열, token 문자열, 또는 hex 문자열 중 하나예요.

모든 문자열 리터럴 형식에서, EndOfLine은 단일 \n 문자 하나로 취급돼요.

Wysiwyg 문자열 (Wysiwyg Strings)

WysiwygString:
    r" WysiwygCharactersopt " StringPostfixopt

AlternateWysiwygString:
    ` WysiwygCharactersopt ` StringPostfixopt

WysiwygCharacters:
    WysiwygCharacter
    WysiwygCharacter WysiwygCharacters

WysiwygCharacter:
    Character
    EndOfLine

Wysiwyg(“what you see is what you get”, 보이는 그대로) 문자열은 두 가지 문법 중 하나로 정의할 수 있어요.

첫 번째 형식은 r"" 사이에 감싸는 방식이에요. r"" 사이의 모든 문자가 전부 문자열의 일부가 되죠. wysiwyg 문자열 안에는 이스케이프 시퀀스가 전혀 없어요.

r"I am Oz"
r"c:\games\Sudoku.exe"
r"ab\n" // string is 4 characters,
        // 'a', 'b', '\', 'n'

또는 wysiwyg 문자열을 백쿼트(backquote) ` 문자로 감쌀 수도 있어요.

`the Great and Powerful.`
`c:\games\Empire.exe`
`The "lazy" dog`
`a"b\n`  // string is 5 characters,
         // 'a', '"', 'b', '\', 'n'

함께 보기: InterpolatedWysiwygLiteral

이중 따옴표 문자열 (Double Quoted Strings)

DoubleQuotedString:
    " DoubleQuotedCharactersopt " StringPostfixopt

DoubleQuotedCharacters:
    DoubleQuotedCharacter
    DoubleQuotedCharacter DoubleQuotedCharacters

DoubleQuotedCharacter:
    Character
    EscapeSequence
    EndOfLine

이중 따옴표 문자열은 "로 감싸요. 그 안에는 이스케이프 시퀀스(EscapeSequence) 를 넣을 수 있어요.

"Who are you?"
"c:\\games\\Doom.exe"
"ab\n"   // string is 3 characters,
         // 'a', 'b', and a linefeed
"ab
"        // string is 3 characters,
         // 'a', 'b', and a linefeed

함께 보기: InterpolatedDoubleQuotedLiteral

Delimited 문자열 (Delimited Strings)

DelimitedString:
    q" Delimiter WysiwygCharactersopt MatchingDelimiter " StringPostfixopt
    q"( ParenDelimitedCharactersopt )" StringPostfixopt
    q"[ BracketDelimitedCharactersopt ]" StringPostfixopt
    q"{ BraceDelimitedCharactersopt }" StringPostfixopt
    q"< AngleDelimitedCharactersopt >" StringPostfixopt

Delimiter:
    Identifier

MatchingDelimiter:
    Identifier

ParenDelimitedCharacters:
    WysiwygCharacter
    WysiwygCharacter ParenDelimitedCharacters
    ( ParenDelimitedCharactersopt )

BracketDelimitedCharacters:
    WysiwygCharacter
    WysiwygCharacter BracketDelimitedCharacters
    [ BracketDelimitedCharactersopt ]

BraceDelimitedCharacters:
    WysiwygCharacter
    WysiwygCharacter BraceDelimitedCharacters
    { BraceDelimitedCharactersopt }

AngleDelimitedCharacters:
    WysiwygCharacter
    WysiwygCharacter AngleDelimitedCharacters
    < AngleDelimitedCharactersopt >

Delimited 문자열은 다양한 형태의 구분자(delimiter) 를 사용해요. 구분자(문자든 식별자든)는 공백 없이 " 바로 뒤에 와야 해요. 그리고 종료 구분자는 공백 없이 닫는 " 바로 앞에 와야 하죠. 중첩 구분자(nesting delimiter) 는 중첩이 허용되며, 다음 문자 중 하나예요:

Nesting Delimiters

Delimiter Matching Delimiter
[ ]
( )
< >
{ }
q"(foo(xxx))"   // "foo(xxx)"
q"[foo{]"       // "foo{"

구분자가 식별자라면, 그 식별자 바로 뒤에 새 줄(newline)이 와야 하고, 짝이 되는 구분자도 같은 식별자여야 하며 줄의 처음에서 시작해야 해요:

writeln(q"EOS
This
is a multi-line
heredoc string
EOS"
);

여는 식별자 다음의 새 줄은 문자열의 일부가 아니지만, 닫는 식별자 바로 앞의 마지막 새 줄은 문자열의 일부가 돼요. 닫는 식별자는 반드시 맨 왼쪽 열에서 자기 줄에 위치해야 해요.

그 외의 경우, 짝 구분자는 구분자 문자 자체와 같아요:

q"/foo]/"          // "foo]"
// q"/abc/def/"    // error

Token 문자열 (Token Strings)

TokenString:
    q{ TokenStringTokensopt } StringPostfixopt

TokenStringTokens:
    TokenStringToken
    TokenStringToken TokenStringTokens

TokenStringToken:
    TokenNoBraces
    { TokenStringTokensopt }

Token 문자열은 q{로 시작해서 } 토큰으로 닫혀요. 그 사이에는 유효한 D 토큰이 와야 해요. {} 토큰은 중첩될 수 있고, 문자열은 주석을 포함해서 token 문자열의 여는 부분과 닫는 부분 사이의 모든 문자로 만들어져요.

q{this is the voice of} // "this is the voice of"
q{/*}*/ }               // "/*}*/ "
q{ world(q{control}); } // " world(q{control}); "
q{ __TIME__ }           // " __TIME__ "
                        // i.e. it is not replaced with the time
// q{ __EOF__ }         // error
                        // __EOF__ is not a token, it's end of file

함께 보기: InterpolatedTokenLiteral

Hex 문자열 (Hex Strings)

HexString:
    x" HexStringCharsopt " StringPostfixopt

HexStringChars:
    HexStringChar
    HexStringChar HexStringChars

HexStringChar:
    HexDigit
    WhiteSpace
    EndOfLine

Hex 문자열은 hex 데이터로 문자열 리터럴을 만들 수 있게 해줘요. 이 hex 데이터는 유효한 UTF 문자를 이룰 필요가 없어요.

x"0A"              // same as "\x0A"
x"00 FBCD 32FD 0A" // same as "\x00\xFB\xCD\x32\xFD\x0A"

공백과 새 줄은 무시되므로 hex 데이터를 쉽게 포맷할 수 있어요. hex 문자 개수는 2의 배수여야 해요.

문자열 접미사 (String Postfix)

StringPostfix:
    c
    w
    d

선택적인 StringPostfix 문자는 문자열에 특정 타입을 부여해요. 문맥에서 추론되는 대신이죠. 접미사 문자에 대응하는 타입은 다음과 같아요:

String Literal Postfix Characters

Postfix Type Alias
c immutable(char)[] string
w immutable(wchar)[] wstring
d immutable(dchar)[] dstring
"hello"c  // string
"hello"w  // wstring
"hello"d  // dstring

문자열 리터럴은 UTF-8 char 배열로 조립된 다음, 마지막 단계에서 접미사에 따라 wchardchar로 변환이 적용돼요.

이스케이프 시퀀스 (Escape Sequences)

EscapeSequence:
    \'
    \"
    \?
    \\
    \0
    \a
    \b
    \f
    \n
    \r
    \t
    \v
    \x HexDigit HexDigit
    \ OctalDigit
    \ OctalDigit OctalDigit
    \ OctalDigit OctalDigit OctalDigit
    \u HexDigit HexDigit HexDigit HexDigit
    \U HexDigit HexDigit HexDigit HexDigit HexDigit HexDigit HexDigit HexDigit
    \ NamedCharacterEntity

OctalDigit:
    0
    1
    2
    3
    4
    5
    6
    7

Escape Sequences

Sequence Meaning
' Literal single-quote: '
" Literal double-quote: "
? Literal question mark: ?
\ Literal backslash: \
\0 Binary zero (NUL, U+0000).
\a BEL (alarm) character (U+0007).
\b Backspace (U+0008).
\f Form feed (FF) (U+000C).
\n End-of-line (U+000A).
\r Carriage return (U+000D).
\t Horizontal tab (U+0009).
\v Vertical tab (U+000B).
\xnn Byte value in hexadecimal, where nn is specified as two hexadecimal digits.For example: \xFF represents the character with the value 255. See also: std.conv.hexString.
\n\nn\nnn Byte value in octal.For example: \101 represents the character with the value 65 ('A'). Analogous to hexadecimal characters, the largest byte value is \377 (= \xFF in hexadecimal or 255 in decimal) See also: std.conv.octal.
\unnnn Unicode character U+nnnn, where nnnn are four hexadecimal digits.For example, \u03B3 represents the Unicode character γ (U+03B3 - GREEK SMALL LETTER GAMMA).
\Unnnnnnnn Unicode character U+nnnnnnnn, where nnnnnnnn are 8 hexadecimal digits.For example, \U0001F603 represents the Unicode character U+1F603 (SMILING FACE WITH OPEN MOUTH).
\name Named character entity from the HTML5 specification. These names begin with & and end with ;, e.g., €. See NamedCharacterEntity.

문자 리터럴 (Character Literals)

CharacterLiteral:
    ' SingleQuotedCharacter '

SingleQuotedCharacter:
    Character
    EscapeSequence

문자 리터럴은 작은 따옴표로 감싼 하나의 문자 또는 이스케이프 시퀀스예요.

'h'   // the letter h
'\n'  // newline
'\\'  // the backslash character

문자 리터럴은 char, wchar, dchar 중 하나의 타입으로 결정돼요 (Basic Data Types 참고).

  • 리터럴이 \u 이스케이프 시퀀스면 wchar 타입으로 결정돼요.
  • 리터럴이 \U 이스케이프 시퀀스면 dchar 타입으로 결정돼요.

그 외에는 들어갈 수 있는 가장 작은 크기의 타입으로 결정돼요.

정수 리터럴 (Integer Literals)

IntegerLiteral:
    Integer
    Integer IntegerSuffix

Integer:
    DecimalInteger
    BinaryInteger
    HexadecimalInteger

IntegerSuffix:
    L
    u
    U
    Lu
    LU
    uL
    UL
DecimalInteger:
    0 Underscoresopt
    NonZeroDigit
    NonZeroDigit DecimalDigitsUS

Underscores:
    _
    Underscores _

NonZeroDigit:
    1
    2
    3
    4
    5
    6
    7
    8
    9

DecimalDigits:
    DecimalDigit
    DecimalDigit DecimalDigits

DecimalDigitsUS:
    DecimalDigitUS
    DecimalDigitUS DecimalDigitsUS

DecimalDigitsNoSingleUS:
    DecimalDigitsUSopt DecimalDigit DecimalDigitsUSopt

DecimalDigitsNoStartingUS:
    DecimalDigit
    DecimalDigit DecimalDigitsUS

DecimalDigit:
    0
    NonZeroDigit

DecimalDigitUS:
    DecimalDigit
    _
BinaryInteger:
    BinPrefix BinaryDigitsNoSingleUS

BinPrefix:
    0b
    0B

BinaryDigitsNoSingleUS:
    BinaryDigitsUSopt BinaryDigit BinaryDigitsUSopt

BinaryDigitsUS:
    BinaryDigitUS
    BinaryDigitUS BinaryDigitsUS

BinaryDigit:
    0
    1

BinaryDigitUS:
    BinaryDigit
    _
HexadecimalInteger:
    HexPrefix HexDigitsNoSingleUS

HexDigits:
    HexDigit
    HexDigit HexDigits

HexDigitsUS:
    HexDigitUS
    HexDigitUS HexDigitsUS

HexDigitsNoSingleUS:
    HexDigitsUSopt HexDigit HexDigitsUSopt

HexDigitsNoStartingUS:
    HexDigit
    HexDigit HexDigitsUS

HexDigit:
    DecimalDigit
    HexLetter

HexDigitUS:
    HexDigit
    _

HexLetter:
    a
    b
    c
    d
    e
    f
    A
    B
    C
    D
    E
    F

정수는 십진수(decimal), 이진수(binary), 또는 십육진수(hexadecimal) 로 지정할 수 있어요.

  • 십진수 정수는 십진 숫자의 나열이에요.
  • 이진수 정수는 0b 또는 0B로 시작하는 이진 숫자의 나열이에요.
  • C 스타일의 8진수 표기법(예: 0167)은 십진 표기와 혼동되기 쉽다고 판단되어, 문자열 리터럴에서만 완전히 지원돼요. D는 여전히 std.conv.octal 템플릿(예: octal!167)을 통해 컴파일 타임에 해석되는 8진수 정수 리터럴을 지원해요.
  • 십육진수 정수는 0x 또는 0X로 시작하는 십육진 숫자의 나열이에요.
10      // decimal
0b1010  // binary
0xA     // hex

정수는 가독성을 위해 숫자 다음에 _ 문자를 끼워 넣을 수 있는데, 이 _는 무시돼요.

20_000        // leagues under the sea
867_5309      // number on the wall
1_522_000     // thrust of F1 engine (lbf sea level)
0xBAAD_F00D   // magic number for debugging

정수 바로 뒤에는 L 하나, 또는 u·U 중 하나, 또는 둘 다가 올 수 있어요. l(소문자 L) 접미사는 없다는 점을 기억하세요.

정수의 타입은 다음과 같이 결정돼요:

Decimal Literal Types

Literal Type
0 .. 2_147_483_647 int
2_147_483_648 .. 9_223_372_036_854_775_807 long
9_223_372_036_854_775_808 .. 18_446_744_073_709_551_615 ulong
0L .. 9_223_372_036_854_775_807L long
0U .. 4_294_967_295U uint
4_294_967_296U .. 18_446_744_073_709_551_615U ulong
0UL .. 18_446_744_073_709_551_615UL ulong
0x0 .. 0x7FFF_FFFF int
0x8000_0000 .. 0xFFFF_FFFF uint
0x1_0000_0000 .. 0x7FFF_FFFF_FFFF_FFFF long
0x8000_0000_0000_0000 .. 0xFFFF_FFFF_FFFF_FFFF ulong
0x0L .. 0x7FFF_FFFF_FFFF_FFFFL long
0x8000_0000_0000_0000L .. 0xFFFF_FFFF_FFFF_FFFFL ulong
0x0U .. 0xFFFF_FFFFU uint
0x1_0000_0000U .. 0xFFFF_FFFF_FFFF_FFFFU ulong
0x0UL .. 0xFFFF_FFFF_FFFF_FFFFUL ulong

정수 리터럴은 이 값들을 초과할 수 없어요.

모범 사례(Best Practices):

정수 리터럴에는 8진수 표기법이 지원되지 않아요. 하지만 8진수 정수 리터럴은 std.conv.octal 템플릿(예: octal!167)을 통해 컴파일 타임에 해석할 수 있어요.

부동소수점 리터럴 (Floating Point Literals)

FloatLiteral:
    Float Suffixopt
    Integer FloatSuffix ImaginarySuffixopt
    Integer RealSuffixopt ImaginarySuffix

Float:
    DecimalFloat
    HexFloat

DecimalFloat:
    LeadingDecimal . DecimalDigitsNoStartingUSopt
    LeadingDecimal . DecimalDigitsNoStartingUS DecimalExponent
    . DecimalDigitsNoStartingUS DecimalExponentopt
    LeadingDecimal DecimalExponent

DecimalExponent:
    DecimalExponentStart DecimalDigitsNoSingleUS

DecimalExponentStart:
    e
    E
    e+
    E+
    e-
    E-

HexFloat:
    HexPrefix HexDigitsNoSingleUS . HexDigitsNoStartingUS HexExponent
    HexPrefix . HexDigitsNoStartingUS HexExponent
    HexPrefix HexDigitsNoSingleUS HexExponent
    HexPrefix HexExponent

HexPrefix:
    0x
    0X

HexExponent:
    HexExponentStart DecimalDigitsNoSingleUS

HexExponentStart:
    p
    P
    p+
    P+
    p-
    P-


Suffix:
    FloatSuffix ImaginarySuffixopt
    RealSuffix ImaginarySuffixopt
    ImaginarySuffix

FloatSuffix:
    f
    F

RealSuffix:
    L

ImaginarySuffix:
    i

LeadingDecimal:
    DecimalInteger
    0 DecimalDigitsNoSingleUS

부동소수점(실수) 리터럴은 십진 또는 십육진 형식이 될 수 있고, 숫자 하나 이상소수점·지수·FloatSuffix 중 하나를 반드시 가져야 해요.

십진 실수는 e 또는 E 다음에 오는 십진 수를 10의 지수로 갖는 지수를 가질 수 있어요.

-1.0
1e2               // 100.0
1e-2              // 0.01
-1.175494351e-38F // float.min

십육진 실수는 0x0X로 시작하고, 지수는 p 또는 P 다음에 오는 십진 수를 2의 지수로 사용해요.

0xAp0                  // 10.0
0x1p2                  // 4.0
0x1.FFFFFFFFFFFFFp1023 // double.max
0x1p-52                // double.epsilon

실수 리터럴도 가독성을 위해 숫자 다음에 _ 문자를 끼워 넣을 수 있는데, 무시돼요.

2.645_751
6.022140857E+23
6_022.140857E+20
6_022_.140_857E+20_
  • 접미사가 없는 실수 리터럴은 double 타입이에요.
  • f 또는 F가 뒤따르는 실수 리터럴은 float 타입이에요.
  • L이 뒤따르는 실수 리터럴은 real 타입이에요.
0.0                    // double
0F                     // float
0.0L                   // real

리터럴은 타입의 범위를 넘을 수 없어요. 리터럴은 타입의 유효 숫자(significant digit)에 맞게 반올림돼요.

만약 실수 리터럴이 .과 타입 접미사를 모두 가진다면, 반드시 그 사이에 숫자가 하나 이상 있어야 해요:

1f;  // OK, float
1.f; // error
1.;  // OK, double

참고(Note):

허수(imaginary) 부동소수점 값을 나타내는 i 접미사가 붙은 실수 리터럴은 더 이상 사용되지 않아요(deprecated).

키워드 (Keywords)

키워드는 예약된 식별자예요.

Keyword:
    abstract
    alias
    align
    asm
    assert
    auto

    body
    bool
    break
    byte

    case
    cast
    catch
    cdouble
    cent
    cfloat
    char
    class
    const
    continue
    creal

    dchar
    debug
    default
    delegate
    delete
    deprecated
    do
    double

    else
    enum
    export
    extern

    false
    final
    finally
    float
    for
    foreach
    foreach_reverse
    function

    goto

    idouble
    if
    ifloat
    immutable
    import
    in
    inout
    int
    interface
    invariant
    ireal
    is

    lazy
    long

    macro
    mixin
    module

    new
    nothrow
    null

    out
    override

    package
    pragma
    private
    protected
    public
    pure

    real
    ref
    return

    scope
    shared
    short
    static
    struct
    super
    switch
    synchronized

    template
    this
    throw
    true
    try
    typeid
    typeof

    ubyte
    ucent
    uint
    ulong
    union
    unittest
    ushort

    version
    void

    wchar
    while
    with

    __FILE__
    __FILE_FULL_PATH__
    __FUNCTION__
    __LINE__
    __MODULE__
    __PRETTY_FUNCTION__

    __gshared
    __parameters
    __rvalue
    __traits
    __vector

특수 토큰 (Special Tokens)

이 토큰들은 다음 표에 따라 다른 토큰으로 치환돼요:

Special Tokens

Special Token Replaced with
DATE string literal of the date of compilation "mmm dd yyyy"
EOF tells the scanner to ignore everything after this token
TIME string literal of the time of compilation "hh:mm:ss"
TIMESTAMP string literal of the date and time of compilation "www mmm dd hh:mm:ss yyyy"
VENDOR Compiler vendor string
VERSION Compiler version as an integer

구현 정의(Implementation Defined):

__VENDOR__의 치환 문자열 리터럴과 __VERSION__의 치환 정수 값.

특수 토큰 시퀀스 (Special Token Sequences)

SpecialTokenSequence:
    # line IntegerLiteral Filespecopt EndOfLine
    # line __LINE__ Filespecopt EndOfLine
Filespec:
    " DoubleQuotedCharactersopt "

특수 토큰 시퀀스는 어휘 분석기가 처리하며, 다른 토큰들 사이 어디에든 나타날 수 있고 구문 분석에는 영향을 주지 않아요.

특수 토큰 시퀀스는 시퀀스 시작의 첫 번째 # 토큰 뒤에 오는 첫 번째 새 줄에서 종료돼요.

현재 특수 토큰 시퀀스는 #line 하나뿐이에요.

#line은 다음 소스 줄의 줄 번호와 (선택적으로) 현재 소스 파일 이름을, 다음 줄부터 시작해서 바꿔줘요. 예를 들어:

int #line 6 "pkg/mod.d"
x;  // this is now line 6 of file pkg/mod.d

구현 정의(Implementation Defined):

소스 파일과 줄 번호는 주로 오류 메시지를 출력하거나, 생성된 코드를 심볼릭 디버깅 출력을 위해 원본 소스에 다시 매핑할 때 사용돼요.

더 알아보기 (Learn more)