在D中,词法分析独立于语法分析和语义分析。词法分析器将源文件分割成记号。词法描述了如何识别记号。D的词法被设计为适于高速扫描,它拥有最小的特殊规则集合,只有一遍翻译,这使得构造一个正确的扫描程序很容易。对于熟悉
C 和 C++ 的人来说,记号也很容易识别。
编译的阶段
编译被分为多个阶段。每个阶段都不依赖于后继的阶段。例如,扫描程序不依赖于语义分析程序。这种分离使语法制导编辑器等语言工具相对容易构造。这也使通过将其存储为‘符号’形式来压缩
D 源码成为可能。
- 源码字符集
先检查源文件使用的是什么字符集,然后使用合适的扫描程序。可以使用 ASCII 或 UTF 格式。
- 词法分析
源文件被分割为记号序列。特殊记号会被处理,然后删除。
- 语法分析
符号序列被解析为语法树。
- 语义分析
遍历语法树,声明变量、载入符号表、分配型别并从大体上决定程序的意义。
- 优化
优化是可选的一步,它试图语义等价的重写程序,但是生成一个更为快速的版本。
- 代码生成
采用目标架构的指令来实现程序的语义。典型的结果是生成一个目标文件,它会作为连接器的输入。
源码文本
D 源码文本可以是下面各种形式之一:
- ASCII
- UTF-8
- UTF-16BE
- UTF-16LE
- UTF-32BE
- UTF-32LE
UTF-8 是传统的7位 ASCII 的超集。 源代码文档的开始可以是下面的任一个 UTF BOMs(字节序标志)之一:
格式 |
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 |
D 中没有“双连符”或者“三连符” 。 (译注:三连符是一些由 ?? 开头的连续的三字符组合,它包括
??=,??/,??',??(,??),??!,??<,??>和??-,这些字符将被直接替换为对应的字符,分别为#,,^,[,],
|,{,}和~。引入三连符是为了方便的输入这些字符,早期有些键盘不支持它们。双连符同理。显然 Walter 认为这些东西早就过时了。)
源代码文档由 空白、行尾、注释、特殊记号序列、记号等组成,结尾处必须是 文件尾 。
应使用贪心算法将源代码文档分割为记号,也就是词法分析器每次都试图生成一个最长的符号。例如:>>
是一个右移运算符,而不是两个大于运算符。
文件尾: 文件的物理结尾 \u0000 \u001A
EndOfFile: physical end of the file \u0000 \u001A
在遇到上述之一时认为文件终止。
行尾: \u000D \u000A \u000D \u000A 文件尾
EndOfLine: \u000D \u000A \u000D \u000A EndOfFile
不允许用反斜线来将一行分为多行,行长度也没有限制。
空白: 空格 空格 空白 空格: \u0020 \u0009 \u000B \u000C 行尾 注释
WhiteSpace: Space Space WhiteSpace Space: \u0020 \u0009 \u000B \u000C EndOfLine Comment
空白被定义为一系列的一个或多个空格、制表符、垂直制表符、表格填充、行尾或者注释。
注释: /* 字符 */ // 字符 行尾 /+ 字符 +/
Comment: /* Characters */ // Characters EndOfLine /+ Characters +/
D 有三种注释:
- 块注释可以跨越多行,但是不能嵌套。
- 单行注释在行尾结束。
- 嵌套注释可以跨越多行并且可以嵌套。
从概念上来说,在记号化之前处理注释。这意味着嵌入的字符串和注释不会影响对注释开始和注释结束的识别:
a = /+ // +/ 1; // 解析为 'a = 1;'
a = /+ "+/" +/ 1"; // 解析为 'a = " +/1";'
a = /+ /* +/ */ 3; // 解析为 'a = */ 3;'
注释不能被用作记号连接符,例如 abc/**/def
是两个符号,abc 和 def
,而不是记号 abcdef 。
记号: 标志符 字符串文字量 字符文字量 整数文字量 浮点数文字量 关键字
Token: Identifier StringLiteral CharacterLiteral IntegerLiteral FloatLiteral Keyword
/ /= . .. ... & &= && | |= || - -= -- +
+= ++ < <= << <<= <> <>= > >= >>= >>>= >> >>> !
!= !== !<> !<>= !< !<= !> !>= ( ) [ ] { } ?
, ; : $ = == === * *= % %= ^ ^= ~ ~=
标志符: 标志符起始 标志符起始 多个标志符字符 多个标志符字符: 标志符字符 标志符字符 多个标志符字符
Identifier: IdentiferStart IdentiferStart IdentifierChars IdentifierChars: IdentiferChar IdentiferChar IdentifierChars
标志符起始: _ 字母 通用字母 标志符字符: 标志符起始 数字
IdentifierStart: _ Letter UniversalAlpha IdentifierChar: IdentiferStart Digit
标志符由一个字母、下划线或者一个 unicode 字母开头,后面跟着任意个字母、下划线、数字或者通用字母。通用字母的定义请参考 ISO/IEC
9899:1999(E) 附录 D 。(这是 C99 标准) 标志符长度任意,并且区分大小写。以两个下划线开头的标志符是保留的。