yidabu 2007-4-21 11:31
3 D语言 词法 Lexical
3 D语言 词法 Lexical知识若不分享 实在没有意义 http://www.d-programming-language-china.org 20070416点击下面网址查看原文:http://www.d-programming-language-china.org by: uFramer uframer@sina100.com D语言论坛 http://www.d-programming-language-china.org from: http://www.digitalmars.com/d/lex.html version: 基于D 1.012 (Apr 12, 2007) 在 D 中,词法分析独立于语法分析和语义分析。词法分析器将源文件分割成记号。词法描述了如何识别记号。D 的词法被设计为适于高速扫描,它拥有最小的特殊规则集合,只有一遍翻译,这使得构造一个正确的扫描程序很容易。对于熟悉 C 和 C++ 的人来说,记号也很容易识别。编译的阶段 编译被分为多个阶段。每个阶段都不依赖于后继的阶段。例如,扫描程序不依赖于语义分析程序。这种分离使语法制导编辑器等语言工具相对容易构造。这也使通过将其存储为‘符号’形式来压缩 D 源码成为可能。 1 源码字符集 先检查源文件使用的是什么字符集,然后使用合适的扫描程序。可以使用 ASCII 或 UTF 格式。 2 脚本行 如果第一行开始于#!则第一行被忽略。 D语言论坛 http://www.d-programming-language-china.org 按: 还记得本系列 D语言文档的第一篇吗,最后的hello world示例代码的的第一行就是: [Copy to clipboard] [ - ]CODE: #!/usr/bin/dmd -run 3 词法分析 源文件被分割为记号序列。特殊记号会被处理,然后删除。 4 语法分析 符号序列被解析为语法树。( 本文出处: http://www.d-programming-language-china.org ) 5 语义分析 遍历语法树,声明变量、载入符号表、分配型别并从大体上决定程序的意义。 6 优化 优化是可选的一步,它试图语义等价的重写程序,但是生成一个更为快速的版本。 7 代码生成 采用目标架构的指令来实现程序的语义。典型的结果是生成一个目标文件,它会作为连接器的输入。源码文本 D 源码文本可以是下面各种形式之一: ASCII UTF-8 UTF-16BE UTF-16LE UTF-32BE UTF-32LE UTF-8 是传统的7位 ASCII 的超集。 源代码文档的开始可以是下面的任一个 UTF BOMs(字节序标志Byte Order Marks)之一:( 本文出处: http://www.d-programming-language-china.org ) QUOTE: 格式 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 no BOM 如果源文件没有从BOM开始,那么第一个字符必须小于或等于U0000007F D 中没有“双连符”或者“三连符” 。(译注:三连符是一些由 ?? 开头的连续的三字符组合,它包括 ??=,??/,??',??(,??),??!,??和??-,这些字符将被直接替换为对应的字符,分别为#,,^,[,],|,{,}和~。引入三连符是为了方便的输入这些字符,早期有些键盘不支持它们。双连符同理。显然 Walter 认为这些东西早就过时了。) 源文本从源表示法译码为Unicode字符。源代码文档由 空白、行尾、注释、特殊记号序列、记号等组成,结尾处必须是 文件尾 。 应使用贪心算法将源代码文档分割为记号,也就是词法分析器每次都试图生成一个最长的符号。例如:>> 是一个右移运算符,而不是两个大于运算符。文件尾 文件的物理结尾( 本文出处: http://www.d-programming-language-china.org ) QUOTE: \u0000 \u001A 在遇到上述之一时认为文件终止。行尾 QUOTE: \u000D \u000A \u000D \u000A 文件尾 不允许用反斜线来将一行分为多行,行长度也没有限制。空白 QUOTE: WhiteSpace: Space Space WhiteSpace Space: \u0020 \u0009 \u000B \u000C 注释 QUOTE: Comment: /* Characters */ // Characters EndOfLine NestingBlockComment Characters: Character Character Characters NestingBlockComment: /+ NestingBlockCommentCharacters +/ NestingBlockCommentCharacters: NestingBlockCommentCharacter NestingBlockCommentCharacter NestingBlockCommentCharacters NestingBlockCommentCharacter: Character NestingBlockComment D 有三种注释: 1 块注释可以跨越多行,但是不能嵌套 2 单行注释在行尾结束 3 嵌套注释可以跨越多行并且可以嵌套 从概念上来说,在记号化之前处理注释。这意味着嵌入的字符串和注释不会影响对注释开始和注释结束的识别: The contents of strings and comments are not tokenized. Consequently, comment openings occurring within a string do not begin a comment, and string delimiters within a comment do not affect the recognition of comment closings and nested "/+" comment openings. With the exception of "/+" occurring within a "/+" comment, comment openings within a comment are ignored.( 本文出处: http://www.d-programming-language-china.org ) QUOTE: a = /+ // +/ 1; // 解析为 'a = 1;' a = /+ "+/" +/ 1"; // 解析为 'a = " +/1";' a = /+ /* +/ */ 3; // 解析为 'a = */ 3;' 注释不能被用作记号连接符,例如 abc/**/def 是两个符号,abc 和 def ,而不是记号 abcdef 。记号 QUOTE: Token: Identifier StringLiteral CharacterLiteral IntegerLiteral FloatLiteral Keyword / /= . .. ... & &= && | |= || - -= -- + += ++ < <= << <<= <> <>= > >= >>= >>>= >> >>> ! != !<> !<>= !< !<= !> !>= ( ) [ ] { } ? , ; : $ = == * *= % %= ^ ^= ~ ~= 标志符 QUOTE: Identifier: IdentiferStart IdentiferStart IdentifierChars IdentifierChars: IdentiferChar IdentiferChar IdentifierChars IdentifierStart: _ Letter UniversalAlpha IdentifierChar: IdentiferStart 0 NonZeroDigit 标志符由一个字母、下划线或者一个 unicode 字母开头,后面跟着任意个字母、下划线、数字或者通用字母。通用字母的定义请参考 ISO/IEC 9899:1999(E) 附录 D 。(这是 C99 标准) 标志符长度任意,并且区分大小写。以两个下划线开头的标志符是保留的。字符串文字量 QUOTE: 字符串文字量: 所见即所得字符串 替代所见即所得字符串 双引号字符串 转义序列 十六进制字符串 所见即所得字符串: r" 多个所见即所得字符 " 替代所见即所得字符串: ` 多个所见即所得字符 ` 所见即所得字符: 字符 行尾 双引号字符串: " 多个双引号字符 " 双引号字符: 字符 转义序列 行尾 转义序列: \' \" \? \\ \a \b \f \n \r \t \v \ 文件尾 \x 十六进制数字 十六进制数字 \ 八进制数字 \ 八进制数字 八进制数字 \ 八进制数字 八进制数字 八进制数字 \u 十六进制数字 十六进制数字 十六进制数字 十六进制数字 \U 十六进制数字 十六进制数字 十六进制数字 十六进制数字 十六进制数字 十六进制数字 十六进制数字 十六进制数字 十六进制字符串: x" 多个十六进制字符串字符 " 多个十六进制字符串字符: 十六进制数字 空白 行尾 StringLiteral: WysiwygString AlternateWysiwygString DoubleQuotedString EscapeSequence HexString WysiwygString: r" WysiwygCharacters " Postfix opt AlternateWysiwygString: ` WysiwygCharacters ` Postfix opt WysiwygCharacters: WysiwygCharacter WysiwygCharacter WysiwygCharacters WysiwygCharacter: Character EndOfLine DoubleQuotedString: " DoubleQuotedCharacters " Postfix opt DoubleQuotedCharacters: DoubleQuotedCharacter DoubleQuotedCharacter DoubleQuotedCharacters DoubleQuotedCharacter: Character EscapeSequence EndOfLine EscapeSequence: \' \" \? \\ \a \b \f \n \r \t \v \ EndOfFile \x HexDigit HexDigit \ OctalDigit \ OctalDigit OctalDigit \ OctalDigit OctalDigit OctalDigit \u HexDigit HexDigit HexDigit HexDigit \U HexDigit HexDigit HexDigit HexDigit HexDigit HexDigit HexDigit HexDigit \& NamedCharacterEntity ; HexString: x" HexStringChars " Postfixopt HexStringChars: HexStringChar HexStringChar HexStringChars HexStringChar HexDigit WhiteSpace EndOfLine Postfix c w d 字符串文字量可以是一个双引号字符串、一个所见即所得引号字符串、一个转义序列、或者一个十六进制字符串。 所见即所得引号字符串由‘r"’和‘"’包围起来。所有位于‘r"’和‘"’之间的字符都是字符串的一部分,只有 行尾 除外,他被视作一个‘\n’字符。在 r" " 中没有转义序列: QUOTE: r"hello" r"c:\root\foo.exe" r"ab\n" // 由四个字符组成的字符串:'a'、'b'、'\'、'n' 所见即所得字符串的另一种形式是使用反引号‘`’代替双引号。‘`’字符并不是所有的键盘上都有,而且有时在屏幕上难以同另一个常用的字符‘'’区分。尽管‘`’很少使用,当用在包含‘"’的字符串时就会体现出它的价值。( 本文出处: http://www.d-programming-language-china.org ) QUOTE: `hello` `c:\root\foo.exe` `ab\n` // 由四个字符组成的字符串:'a'、'b'、'\'、'n' 双引号字符串是用‘""’包围起来的字符串。可以使用典型的‘\’记号在其中嵌入转义序列。行尾 被视作一个‘\n’字符。( 本文出处: http://www.d-programming-language-china.org ) QUOTE: "hello" "c:\\root\\foo.exe" "ab\n" // 由三个字符组成的字符串:'a'、'b'和一个新行符 "ab " // 由三个字符组成的字符串:'a'、'b'和一个新行符 转义字符串由‘\’开始,他和其后的字符构成了一个转义字符序列。相邻的转义字符串会被连接在一起: QUOTE: \n // 新行符 \t // 制表符 \" // 双引号 \012 // 八进制 \x1A // 十六进制 \u1234 // wchar 字符 \U00101234 // dchar 字符 \® //商标 dchar character \r\n // 回车换行 除了上面列出的,其他的转义序列都是非法的。 Although string literals are defined to be composed of UTF characters, the octal and hex escape sequences allow the insertion of arbitrary binary data. \u and \U escape sequences can only be used to insert valid UTF characters. 十六进制字符串使用十六进制数据构造字符串: QUOTE: x"0A" // 等价于 "\x0A" x"00 FBCD 32FD 0A" // 等价于 "\x00\xFB\xCD\x32\xFD\x0A" 空白和新行符会被忽略,因此可以很方便的格式化。十六进制字符的个数必须是2的倍数。 相邻的字符串应该用 ~ 运算符连接,或者也可以仅仅并置即可: QUOTE: "hello " ~ "world" ~ \n // 构成字符串:'h','e','l','l','o',' ','w','o','r','l','d',新行符 下面的形式都是等价的: QUOTE: "ab" "c" r"ab" r"c" r"a" "bc" "a" ~ "b" ~ "c" \x61"bc" 用可选的词尾字符指定了字符串的类型,而不是从从上下文推断。这在不能从上下方明确推断类型时很有用,比如当重载基于字符串的类型时。词尾字符表示的类型如下:( 本文出处: http://www.d-programming-language-china.org ) QUOTE: Postfix Type c char[ ] w wchar[ ] d dchar[ ] 下面是一个例子: [Copy to clipboard] [ - ]CODE: "hello"c // char[] "hello"w // wchar[] "hello"d // dchar[] 字符串文字量只读。写字符串文字量并不是总能发现,但会引发未定义行为。字符文字量 QUOTE: 字符文字量: ' 单引号字符 ' 单引号字符 字符 转义序列 CharacterLiteral: ' SingleQuotedCharacter ' SingleQuotedCharacter Character EscapeSequence 字符文字量是单个的字符或者由单引号括起来的转义序列,' ' 。整数文字量 QUOTE: 整数文字量: 整数 整数 整数后缀 整数: 十进制数 二进制数 八进制数 十六进制数 整数 整数后缀: L u U Lu LU uL UL 十进制数: 0 非零数字 非零数字 十进制数 二进制数: 0b 二进制数字 0B 二进制数字 八进制数: 0 八进制数字 十六进制数: 0x 十六进制数字 0X 十六进制数字 IntegerLiteral: Integer Integer IntegerSuffix Integer: Decimal Binary Octal Hexadecimal Integer IntegerSuffix: L u U Lu LU uL UL Decimal: 0 NonZeroDigit NonZeroDigit DecimalDigits Binary: 0b BinaryDigits 0B BinaryDigits Octal: 0 OctalDigits Hexadecimal: 0x HexDigits 0X HexDigits NonZeroDigit: 1 2 3 4 5 6 7 8 9 DecimalDigits: DecimalDigit DecimalDigit DecimalDigits DecimalDigit: 0 NonZeroDigit _ BinaryDigits: BinaryDigit BinaryDigit BinaryDigits BinaryDigit: 0 1 _ OctalDigits: OctalDigit OctalDigit OctalDigits OctalDigit: 0 1 2 3 4 5 6 7 _ HexDigits: HexDigit HexDigit HexDigits HexDigit: DecimalDigit a b c d e f A B C D E F _ 整数可以采用十进制、二进制、八进制或者十六进制。 十进制整数是十进制数字的序列。 二进制整数是二进制数字的序列,以‘0b’为前缀。( 本文出处: http://www.d-programming-language-china.org ) 八进制整数是八进制数字的序列,以‘0’为前缀。 十六进制整数是十六进制数字的序列,以‘0x’为前缀,或者使用‘h’作为后缀。 整数可以内嵌 '_' 字符,它们会被忽略。嵌入的 '_' 可以用于格式化较长的文字量,例如作为千位分隔符: QUOTE: 123_456 // 123456 1_2_3_4_5_6_ // 123456 整数后可以紧跟着一个 'L' 或者一个 'u' 或者两者都有。 整数的类型按照下述规则判断: QUOTE: Decimal Literal Type 0 .. 2147483647 int 2147483648 .. 9223372036854775807 long Decimal Literal, L Suffix Type 0L .. 9223372036854775807L long Decimal Literal, U Suffix Type 0U .. 4294967295U uint 4294967296U .. 18446744073709551615U ulong Decimal Literal, UL Suffix Type 0UL .. 18446744073709551615UL ulong Non-Decimal Literal Type 0x0 .. 0x7FFFFFFF int 0x80000000 .. 0xFFFFFFFF uint 0x100000000 .. 0x7FFFFFFFFFFFFFFF long 0x8000000000000000 .. 0xFFFFFFFFFFFFFFFF ulong Non-Decimal Literal, L Suffix Type 0x0L .. 0x7FFFFFFFFFFFFFFFL long 0x8000000000000000L .. 0xFFFFFFFFFFFFFFFFL ulong Non-Decimal Literal, U Suffix Type 0x0U .. 0xFFFFFFFFU uint 0x100000000UL .. 0xFFFFFFFFFFFFFFFFUL ulong Non-Decimal Literal, UL Suffix Type 0x0UL .. 0xFFFFFFFFFFFFFFFFUL ulong 浮点数文字量 QUOTE: 浮点数文字量: 浮点数 浮点数 浮点数后缀 浮点数 虚数后缀 浮点数 浮点数后缀 虚数后缀 浮点数: 十进制浮点数 十六进制浮点数 浮点数后缀: f F L 虚数后缀: i FloatLiteral: Float Float FloatSuffix Float ImaginarySuffix Float FloatSuffix ImaginarySuffix Float: DecimalFloat HexFloat DecimalFloat: DecimalDigits . DecimalDigits . DecimalDigits DecimalDigits . DecimalDigits DecimalExponent . Decimal . Decimal DecimalExponent DecimalDigits DecimalExponent DecimalExponent e DecimalDigits E DecimalDigits e+ DecimalDigits E+ DecimalDigits e- DecimalDigits E- DecimalDigits HexFloat: HexPrefix HexDigits . HexDigits HexExponent HexPrefix . HexDigits HexExponent HexPrefix HexDigits HexExponent HexPrefix: 0x 0X HexExponent p DecimalDigits P DecimalDigits p+ DecimalDigits P+ DecimalDigits p- DecimalDigits P- DecimalDigits FloatSuffix: f F L ImaginarySuffix: i 浮点数可以使用十进制或者十六进制格式,如同标准 C 一样。 十六进制浮点数以 0x 开头,阶码以 p 或者 P 开头,后面跟着以 2 为底的阶数。( 本文出处: http://www.d-programming-language-china.org ) 浮点文字量可以有嵌入的‘_’字符,它们会被忽略。嵌入的‘_’用来格式化冗长的文字量以提高可读性,例如可以将它们用作千位分隔符: QUOTE: 123_456.567_8 // 123456.5678 1_2_3_4_5_6_._5_6_7_8 // 123456.5678 1_2_3_4_5_6_._5e-6_ // 123456.5e-6 浮点数没有后缀表示double. 浮点数可以跟随有一个 f、F或者 L 后缀。f 或 F 后缀说明这是一个浮点数,L 说明这是一个real扩展格式浮点数。 如果浮点文字量后面跟着 i 或者 I ,那么它就是一个 ireal (虚数)类型。 示例: QUOTE: 0x1.FFFFFFFFFFFFFp1023 // double.max 0x1p-52 // double.epsilon 1.175494351e-38F // float.min 6.3i // idouble 6.3 6.3fi // ifloat 6.3 6.3Li // ireal 6.3 如果文字量超出了该类型的表示范围,会被视为错误。如果文字量取整后可以用该类型的有效位数字表示,就不是错误。 复数文字量不是记号,而是在语义分析时用实数和虚数表达式构造的: QUOTE: 4.5 + 6.2i // 复数 关键字 关键字是保留的标志符:( 本文出处: http://www.d-programming-language-china.org ) QUOTE: 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 import in inout int interface invariant ireal is lazy long macro mixin module new null out override package pragma private protected public real ref return scope short static struct super switch synchronized template this throw true try typedef typeid typeof ubyte ucent uint ulong union unittest ushort version void volatile wchar while with 特殊记号序列 这些记号按照下面描述替抵成另外的记号: QUOTE: Special Token Replaced with... __FILE__ string literal containing source file name __LINE__ integer literal of the current source line number __DATE__ string literal of the date of compilation "mmm dd yyyy" __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" 特殊记号序列由词法分析程序处理,它可以出现在其他记号之间,并且不影响语法分析。 目前只有一个特殊记号序列,#line 。 QUOTE: 特殊记号序列 # line 整数 行尾 # line 整数 Filespec 行尾 指定文件 " 字符 " SpecialTokenSequence # line Integer EndOfLine # line Integer Filespec EndOfLine Filespec " Characters " 它会将源代码的行号设置为 整数 的值,将源代码文件名设置为可选的 Filespec 的值,从源码文本的下一行生效。 源码文件名和行号用于打印调试信息,还被符号调试器用于将生成的代码映射回源代码。 例如: QUOTE: int #line 6 "foo\bar" x; // 这里是文件 foo\bar 的第6行 注意,Filespec 字符串中的反斜杠不会被特殊对待。( lastupdate:20070421 最新文章请访问http://www.d-programming-language-china.org )关于一大步成功社区:yidabu提倡在交流中学习,在分享中提高收集感兴趣的知识,写下心得,通过网络与别人一起分享理解一点就实践一步,收获什么就分享什么,成功就是这样一点点一步步累积起来的网络只是一个工具,只有自己身心提高才是实实在在的。d-programming-language-china.org为大家提供一个学习交流各种知识的平台